实现读者monad(来自现实世界haskell)

时间:2018-05-07 11:19:09

标签: haskell

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。

提前致谢。

1 个答案:

答案 0 :(得分:7)

  

我很难理解 Reader Monad

编辑: 我应该指出一些资源,而不是尝试重复它们。

  

我认为runReader只需要一个参数,但现在似乎正在接受两个参数,一个是k (runReader m r)而另一个是r

如果您查看runReader :: Reader e a -> e -> a的类型签名,可以将其视为Reader e a并生成e -> a,或者采用Reader e ae并生成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

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

然后运行k a。这会产生mb

然后" mbe"同时运行(runReader mb :: e -> b已应用于e)。

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

我认为理解这一点的困难部分主要与 newtype 需要不断换行(R)和展开({{1} })它的内容,而不是臭名昭着的 monad如何工作

想象一下,你唯一需要的monad就是读者monad,我们可以不用runReadernewtype绒毛。那你的定义可能如下:

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所做的是取两个函数(bindma,又称k (ma e)),它们都期望mb,将它们组合在一个也需要e的新函数中,必须在合成期间明确传递e

我在学习如何编写monad定义时遇到的误解是e 运行任何东西。它在概念上帮助我称之为runReader,因为它所做的就是删除unR包装。