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
我很难理解这两个片段。我可以说第一个是读者的记录语法描述,它具有从e到a的函数runReader,但第二个让我困惑。
通过将m与k绑定,它本质上是在尝试创建一个新的Reader,但是如何
runReader (k (runReader m r)) r
锻炼身体?我认为runReader只接受一个参数,但它似乎现在正在接受两个,一个是k(runReader m r)而另一个是r。
提前致谢。
答案 0 :(得分:7)
我很难理解 Reader Monad 。
编辑: 我应该指出一些资源,而不是尝试重复它们。
我认为
runReader
只需要一个参数,但现在似乎正在接受两个参数,一个是k (runReader m r)
而另一个是r
。
如果您查看runReader :: Reader e a -> e -> a
的类型签名,可以将其视为Reader e a
并生成e -> a
,或者采用Reader e a
和e
并生成a
。读者monad的观点是引入一个隐含的论证。
runReader (k (runReader m r)) r
如何解决问题?
您可以更多地拼出 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
)和展开({{1} })它的内容,而不是臭名昭着的 monad如何工作。
想象一下,你唯一需要的monad就是读者monad,我们可以不用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
,又称k (ma e)
),它们都期望mb
,将它们组合在一个也需要e
的新函数中,必须在合成期间明确传递e
。
我在学习如何编写monad定义时遇到的误解是e
运行任何东西。它在概念上帮助我称之为runReader
,因为它所做的就是删除unR
包装。