ask函数如何知道在Readermonad中返回的环境?
我正在阅读这个关于 Reader monad 的例子:https : //blog.ssanj.net/posts/2014-09-23-A-Simple-Reader-Monad-Example.html有这个代码:
import Control.Monad.Reader
tom :: Reader String String
tom = do
env <- ask -- gives you the environment which in this case is a String
return (env ++ " This is Tom.")
我明白它的作用,但我不明白如何ask返回任何东西。
在 Haskell 中,函数可以作用于许多不同的类型。ask是一个没有输入并返回 monad 环境的函数m r。我试图了解当我这样做时会发生什么
(runReader tom) "Who is this?"
不知怎的,runReader会调用tom,但它是如何可能的ask内tom就能返回一个env与文本Who is this??
回答
doReader monad 中块的每一行都会在后台发送一份环境副本,就好像它是作为额外参数传入的一样(并且由于 Haskell 没有可变数据,每个人都获得了相同的副本)。该ask函数将其副本也作为值返回。
这将有助于用具体类型替换m类型中的泛型ask:ask::Reader r r。此读取ask是一个单子操作,其值(第二个 r)与环境(第一个 r)相同。为了ask有用,Reader r必须存在上下文(这就是do块的用途)。在那个上下文r中总是坐在那里等待被使用。
想一想如何在没有 Monad 的情况下编写此示例:
tom :: String -> String
tom env = env ++ " This is Tom."
jerry :: String -> String
jerry env = env ++ " This is Tom."
tomAndJerry :: String -> String
tomAndJerry env =
let
t = tom env
j = jerry env
in (t ++"n"++j)
注意如何env手动传递给每个函数?(顺便说一下,如果您将Reader r,ask和的定义替换runReader到示例中,您会得到什么。)Reader monad 简单地为我们包装了收集和传递环境的过程,这很好,因为这是我们的过程容易搞砸(至少我是)。
当您有一个在启动时读取一次然后在整个程序的其余部分中引用的配置文件时,Reader Monads 非常方便。在命令式语言中,您可以将其设为全局常量变量。在 Haskell 中,您可以尝试将该值传递给需要它的每个函数,但是将它转储到 Reader monad 中更容易且更不容易出错(并且结果完全相同,只是没有所有输入。)类型系统的附带好处是标记所有依赖于配置文件的功能,因此当配置格式更改时,编译器可以指出所有可能需要更新的位置。