读者monad""如何"功能工作?

时间:2016-04-12 13:09:33

标签: haskell

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(),或者当我们希望函数使用外部数据时,我们必须通过参数传递数据。

2 个答案:

答案 0 :(得分:4)

读者monad 所做的那种;它为您提供了ask功能,其中包括#34;魔法"凭空捏造价值。要实际使用,您需要调用runReader,并为其提供Int环境。然后,Reader类型会自动将runReader次呼叫传播到每个ask来电。

答案 1 :(得分: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类型类定义,并由用于定义ReaderT类型的Reader monad转换器实现,实质上检索传递给的参数的值h

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