Мне трудно понять Монада Читателя .
Редактировать: Я должен указать на ряд ресурсов, а не пытаться повторить их.
Я думал, что runReader
принимает только один аргумент, но, похоже, сейчас он принимает два: один - k (runReader m r)
, а другой - r
.
Если вы посмотрите на сигнатуру типа для runReader :: Reader e a -> e -> a
, это можно рассматривать как либо взятие Reader e a
и получение e -> a
, либо как взятие Reader e a
и e
и получение a
. Цель монады читателя - ввести неявный аргумент.
Как работает runReader (k (runReader m r)) r
? 1060 *
Вы могли бы немного подробнее разъяснить определение оператора bind :
instance Monad (Reader e) where
return a = R $ \_ -> a
-- (>>=) :: Reader e a -> (a -> Reader e b) -> Reader e b
ma >>= k = R $ \e -> let a = runReader ma e
mb = k a
in runReader mb e
То есть сначала "ma
запускается с e
" (runReader ma :: e -> a
применяется к e
). Это производит a
.
Затем k a
запускается. Это производит mb
.
Затем «mb
запускается с e
» (runReader mb :: e -> b
применяется к e
).
Это упаковано в R $ \e -> ... runReader mb e
.
Я пришел к мысли, что сложная часть понимания этого в основном связана с тем, что newtype требует постоянной обертки (R
) и распаковки (runReader
) своего содержимого, скорее чем пресловутый как работают монады .
Представьте, что единственная монада, которая вам когда-либо была нужна, была монада читателя, и мы могли бы обойтись без пуха newtype
и instance Monad (Reader e)
. Тогда ваше определение может выглядеть так:
type Reader e a = e -> a
-- type Reader e a = (->) e a
-- type Reader e = (->) e
unit :: a -> Reader e a
-- :: a -> (e -> a)
unit a = \_e -> a
-- unit a _e = a
-- unit = const
ask :: Reader e e
-- :: e -> e
ask = \e -> e
-- ask e = e
-- ask = id
bind :: Reader e a -> (a -> Reader e b) -> Reader e b
-- :: (e -> a) -> (a -> (e -> b)) -> (e -> b)
bind ma k = \e -> let a = ma e
mb = k a
in mb e
-- bind ma k e = let mb = k (ma e) in mb e
В этот момент становится более ясным, что все, что unit
делает, - отбрасывает e
, ask
делает только возврат e
, и bind
принимает две функции (ma
и * 1108). *, то есть mb
), которые оба ожидают e
, составляют их внутри новой функции, которая также ожидает e
, без необходимости явно передавать e
во время композиции.
Когда я учился писать определения монад, у меня было неправильное представление о том, что runReader
выполняет что-либо. Концептуально это помогло мне назвать его unR
, поскольку все, что он делает - это удаляет обертку R
.