2
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

我很难理解这两个片段。我可以说第一个是具有runReaderfrom eto功能的阅读器的记录语法描述a,但第二个让我感到困惑。

m通过与绑定k,它本质上是在尝试创建一个新的Reader,但是如何

runReader (k (runReader m r)) r

锻炼?我以为runReader只需要一个参数,但现在似乎需要两个参数,一个是存在k (runReader m r),另一个是存在r

提前致谢。

4

1 回答 1

8

我很难理解Reader Monad

编辑:我应该指出一些关于此的资源,而不是试图重复它们。

我以为runReader只需要一个参数,但现在似乎需要两个参数,一个是存在k (runReader m r),另一个是存在r

如果您查看 的类型签名runReader :: Reader e a -> e -> a,则可以将其视为采用 aReader e a并产生 an e -> a,或者视为采用 aReader e a和 ane并产生 a a。reader monad 的重点是引入一个隐含的论点。

效果如何runReader (k (runReader m r)) r

您可以更详细地说明绑定运算符定义:

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

也就是说,首先 "mae" (runReader ma :: e -> a应用于e) 一起运行。这会产生一个a.

然后k a是运行。这会产生一个mb.

然后 "mbe" (runReader mb :: e -> b应用于e) 一起运行。

这被打包成R $ \e -> ... runReader mb e.

我开始认为理解这一点的困难部分主要与newtype需要对其内容进行不断的包装 ( R) 和展开 ( runReader) 的方式有关,而不是臭名昭著的monad 的工作方式


想象一下,你唯一需要的 monad 就是 reader monad,我们可以不用newtypeandinstance 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,并且所做的是接受两个都期望 a 的bind函数(mak (ma e),又名),将它们组合在一个也期望 a 的新函数中,而无需显式在作文过程中通过。mbeee

在学习如何编写 monad 定义时,我自己的一个误解是它runReader 可以运行任何东西。它帮助我在概念上调用它,unR因为它所做的只是去除R包装。

于 2018-05-07T11:34:33.337 回答