【问题标题】:Implementing the Reader monad (from Real World Haskell book)实现 Reader monad(来自 Real World Haskell 书籍)
【发布时间】:2018-10-17 04:30:47
【问题描述】:
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

我很难理解这两个 sn-ps。我可以说第一个是阅读器的记录语法描述,它具有从ea 的函数runReader,但第二个让我感到困惑。

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

runReader (k (runReader m r)) r

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

提前致谢。

【问题讨论】:

    标签: haskell monads reader-monad


    【解决方案1】:

    我很难理解 Reader Monad

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

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

    如果您查看runReader :: Reader e a -> e -> a 的类型签名,这可以看作是采用Reader e a 并产生e -> a,或者采用Reader e ae 并产生@987654334 @。 reader 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) 和展开 (runReader) 其内容的方式有关,而不是臭名昭著的单子如何工作


    想象一下,你唯一需要的 monad 就是 reader monad,我们可以不用 newtypeinstance 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 和@987654360 @,又名mb) 都期望e,将它们组合在一个新函数中,该函数也期望e,而无需在组合过程中显式传递e

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

    【讨论】:

    • 这是一个非常有见地的答案!不过,我需要时间来消化这些材料。你应该得到比我的支持更多的东西!
    • 我现在终于明白了.. 我没有正确理解记录语法。感谢分享。
    猜你喜欢
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多