Haskell 读者如何理解monad';s";询问;功能工作?
我在理解这段代码是如何工作的方面有问题。特别是,Haskell 读者如何理解monad';s";询问;功能工作?,haskell,Haskell,我在理解这段代码是如何工作的方面有问题。特别是,ask如何知道环境在哪里(在我们的例子中就是Int) 更确切地说:我是一个命令式程序员,用这种语言很容易。方法可以在任何对象上调用,比如:obj.f(),或者当我们希望函数使用外部数据时,我们必须通过参数传递数据。这就是读卡器monad所做的;它提供了一个ask函数,可以“神奇地”从稀薄的空气中弹出一个值。要实际使用它,您需要调用runReader,并为其提供Int环境。然后,读卡器类型会自动将该信息从runReader调用传播到每个ask调用。简
ask
如何知道环境在哪里(在我们的例子中就是Int
)
更确切地说:我是一个命令式程序员,用这种语言很容易。方法可以在任何对象上调用,比如:
obj.f()
,或者当我们希望函数使用外部数据时,我们必须通过参数传递数据。这就是读卡器monad所做的;它提供了一个ask
函数,可以“神奇地”从稀薄的空气中弹出一个值。要实际使用它,您需要调用runReader
,并为其提供Int
环境。然后,读卡器
类型会自动将该信息从runReader
调用传播到每个ask
调用。简短的波浪式回答。Reader Int(T Int)
值本质上只是一个类型为Int->(T Int)
的包装函数。为了运行该函数,我们首先需要提取它。我们使用runReader
来实现这一点
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
(通常,您只需编写print$runReader(f tree)20
;我将其拆分以对应下面的粗略类比。)
ask
(由monader
typeclass定义,并由用于定义读取器
类型的ReaderT
monad转换器实现)基本上检索传递给h
的参数值
从某种意义上说,
Reader Int(T Int)
是一个包含调用函数ask
的函数g
的对象runReader g
创建一个新函数,当调用该函数时,该函数定义一个函数ask
,该函数只返回其参数,然后调用g
。现在当g
调用ask
时,它会返回最初传递给h
的参数。这可能是我本周看到的关于二叉树和读卡器单子()的第二个或第三个问题。它是来自MOOC课程作业还是什么?“Reader Int(T Int)值本质上只是Int->(T Int)类型的一个封装函数”这对我来说并不明显,请解释:)我本来打算尝试一下,但也许最好让你看看。它直接定义读取器
monad,而不是从应用于标识monad的转换器(实现类型类)构建它。
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