Внедрение монады Reader (из книги Real World Haskell) - PullRequest
0 голосов
/ 07 мая 2018
newtype Reader e a = R { runReader :: e -> a }

instance Monad (Reader e) where 
  return a = R $ \_ -> a
  m >>= k  = R $ \r -> runReader (k (runReader m r)) r

Мне трудно понять эти два фрагмента. Я могу сказать, что первое - это описание синтаксиса записи для читателя, который имеет функцию runReader от e до a, но второй озадачивает меня.

Связывая m с k, он по сути пытается создать новый Reader, но как это сделать

runReader (k (runReader m r)) r

потренироваться? Я думал, что runReader принимает только один аргумент, но, похоже, сейчас он принимает два аргумента: один - k (runReader m r), а другой - r.

Заранее спасибо.

1 Ответ

0 голосов
/ 07 мая 2018

Мне трудно понять Монада Читателя .

Редактировать: Я должен указать на ряд ресурсов, а не пытаться повторить их.

Я думал, что 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.

...