![](/img/trans.png)
[英]How does the ask function know the enrivonment to return in the Reader monad?
[英]How does the Reader monad's "ask" function work?
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
)?
更准确地说:我是一个命令式程序员,使用这种语言很容易。 可以在任何 object 上调用方法,例如: obj.f()
,或者当我们希望 function 使用外部数据时,我们必须通过参数传递数据。
这就是Reader monad的功能 ; 它为您提供了一个ask
功能,“神奇地”突然弹出一个值。 要实际使用它,您需要调用runReader
,并为其提供Int
环境。 然后, Reader
类型将其自动从runReader
调用传播到每个ask
调用。
简短的手工波浪形答案。 Reader Int (T Int)
值本质上只是Int -> (T Int)
类型的包装函数。 为了运行该功能,我们首先需要提取它。 我们使用runReader
做到这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转换Reader
)基本上检索传递给h
的参数的值。
从某种意义上说, Reader Int (T Int)
是一个包含函数g
的对象,该函数调用函数ask
。 runReader g
创建一个新函数,该函数在被调用时定义一个简单地返回其参数的ask
函数,然后调用g
。 现在,当g
调用ask
,它将返回最初传递给h
的参数。
我建议先阅读这篇文章。 问定义:
ask :: (Monad m) => ReaderT r m r
ask = ReaderT return
和读者:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
type Reader r = ReaderT r Identity
所以
do
r <- ask
...
相当于
do
r <- ReaderT return
...
所以本质上<-
只是进入 identity monad,并获取最终将被runReader R = return
提升的任何价值。
这将启用 haskell 中的全局变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.