繁体   English   中英

Reader monad 的“询问”function 是如何工作的?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM