你能帮助得到什么参数ask吗?我们经常可以看到ask >>= f
这意味着ask >>= f = (\k -> f (ask k) k)
So ask 必须能够从环境中得到 k,函数。
但是,在文档中它是这样写的:ask :: m r. 我哪里错了?
一个类型m awhere mis a Monad 的值可以被认为是一个“monadic action”。所以ask不带任何参数,它只是一个值,您可以绑定 ( >>=) 以从 Reader monad 中提取一些值。
看一下askfor ReaderTin的定义Control.Monad.Trans.Reader:
-- | Fetch the value of the environment.
ask :: (Monad m) => ReaderT r m r
ask = ReaderT return
Run Code Online (Sandbox Code Playgroud)
ReaderT仅仅是一个包含类型的值的数据构造r -> m a,因此ReaderT return是类型的值ReaderT r m r包含一个函数,return(的单子m)。
换句话说,ask这是一个“一元动作”,它提取存储在Reader.
ask >>= f
Run Code Online (Sandbox Code Playgroud)
这是
(ReaderT return) >>= f
Run Code Online (Sandbox Code Playgroud)
使用>>=for Reader 的定义,我们得到:
ReaderT $ \ r -> do
a <- runReaderT (ReaderT return) r
runReaderT (f a) r
Run Code Online (Sandbox Code Playgroud)
这减少到
ReaderT $ \ r -> do
a <- return r
runReaderT (f a) r
Run Code Online (Sandbox Code Playgroud)
或者
ReaderT $ \r -> runReaderT (f r) r
Run Code Online (Sandbox Code Playgroud)
因此,它传递存储的值以决定下一个操作,并传递该值以便下一个操作可以像以前一样读取它。
(如果这还不清楚,请寻找阅读器教程)
这是Reader单子。最终,最好的答案就是研究它的实现,最简单的版本(没有 monad 转换器,没有类)可以这样定义:
newtype Reader r a = Reader { runReader :: r -> a }\nRun Code Online (Sandbox Code Playgroud)\n\n这是一个newtype声明,因此Reader r a只是函数类型的“重新标记”(可以这么说)r -> a。 ask定义如下:
ask :: Reader r r\nask = Reader (\\r -> r)\nRun Code Online (Sandbox Code Playgroud)\n\n这意味着这ask是一个重新标记的恒等函数\xe2\x80\x94,该函数仅返回其自己的参数。如果我们使用runReader如果我们使用该操作向其提供值,
ghci> runReader ask 5\n5\n\nghci> runReader ask "Hello world!"\n"Hello world!"\nRun Code Online (Sandbox Code Playgroud)\n\n这看起来不太有用,但神奇之处在于它Reader有Functor,Applicative和 的实例Monad实例:
instance Functor (Reader r) where\n fmap f (Reader g) =\n -- A `Reader` that applies `f` to the original `Reader`\'s results \n Reader (\\r -> f (g r))\n\ninstance Applicative (Reader r) where\n pure a = \n -- A `Reader` that ignores its `r` argument and just produces\n -- a fixed value.\n Reader (\\_ -> a)\n\n Reader ff <*> Reader fa =\n -- A `Reader` that "combines" two `Reader`s by feeding the same \n -- `r` value to both, and then combining their results \n Reader (\\r -> ff r (fa r))\n\ninstance Monad (Reader r) where\n return = pure\n\n Reader fa >>= k = \n -- A `Reader` that feeds the same `r` both to the original one\n -- and to the one computed by the `k` function\n Reader (\\r -> k (fa r) r)\nRun Code Online (Sandbox Code Playgroud)\n\n如果您研究这些,您会注意到,这Reader会延迟程序中将包装器r -> a函数应用于r. 通常,如果您有一个类型为 的函数r -> a并且想要获取类型为 的值a,则必须向该函数提供类型为 的参数r。类Reader实例允许您提供用于提前操作的函数a,然后提供r。
类型ReaderT和MonadReader类(其中有ask :: MonadReader r m => m r方法)只是其更高级的版本。