【问题标题】:How does the Reader monad's "ask" function work?Reader monad 的“询问”功能是如何工作的?
【发布时间】:2016-08-03 03:04:05
【问题描述】:
data T b = E | N b (T b) (T b) 


f :: T b -> Reader Int (T Int)
f (N i l r) = ask >>= \x ->  local ((-)4) (f l) >>= \l' -> local ((-)1) (f r) >>= \r' -> return (N x l' r')
f E = return E

我无法理解这段代码的工作原理。特别是,ask 如何知道环境在哪里(在我们的例子中只是Int)?

更准确地说:我是一名命令式程序员,使用这种语言很容易。可以在任何对象上调用方法,例如:obj.f(),或者当我们希望函数使用外部数据时,我们必须通过参数传递数据。

【问题讨论】:

  • Reader Monad Purpose的可能重复
  • 这是我本周看到的关于二叉树和阅读器单子的第二个或第三个问题 (eg)。是来自 MOOC 课程作业还是什么?

标签: haskell


【解决方案1】:

这就是 Reader monad 所做的;它为您提供了一个ask 函数,它“神奇地”凭空弹出一个值。要真正使用这个,您需要调用runReader,并为其提供Int 环境。然后,Reader 类型会自动将 runReader 调用中的内容传播到每个 ask 调用。

【讨论】:

    【解决方案2】:

    简短、挥手的回答。 Reader Int (T Int) 值本质上只是 Int -> (T Int) 类型的封装函数。为了运行该函数,我们首先需要提取它。我们使用runReader 来做到这一点。

    data T b = ... deriving (Show)
    
    main = let tree = (N 10 (N 8 E E) E)
               g = f tree
               h = runReader g
           in print $ h 20
    

    (通常,您只需写print $ runReader (f tree) 20;我将其拆分为对应于下面的粗略类比。)

    ask(由MonadReader 类型类定义,并由用于定义Reader 类型的ReaderT monad 转换器实现)实质上检索传递给h 的参数值。

    在某种意义上,Reader Int (T Int) 是一个对象,其中包含一个函数 g,该函数调用一个函数 askrunReader g 创建一个新函数,在调用该函数时,它定义了一个函数ask,它只返回其参数,然后调用g。现在当g 调用ask 时,它会取回最初传递给h 的参数。

    【讨论】:

    • "Reader Int (T Int) 值本质上只是一个 Int 类型的包装函数 -> (T Int)" 这对我来说并不明显,请解释一下 :)
    • 我打算尝试一下,但也许最好将您指向this explanation。它直接定义了一个 Reader monad,而不是从应用于标识 monad 的转换器(实现类型类)构建它。
    猜你喜欢
    • 2021-02-16
    • 2023-04-05
    • 2018-12-12
    • 2017-06-22
    • 2017-08-16
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    相关资源
    最近更新 更多