Haskell读取器monad与参数传递
我正在学习这个教程 它的树函数让我很尴尬Haskell读取器monad与参数传递,haskell,Haskell,我正在学习这个教程 它的树函数让我很尴尬 tom :: Reader String String tom = do env <- ask return (env ++ " This is tom.") jerry :: Reader String String jerry = do env <- ask return (env ++ " This is Jerry.") tomAndJerry :: Reader Strin
tom :: Reader String String
tom = do
env <- ask
return (env ++ " This is tom.")
jerry :: Reader String String
jerry = do
env <- ask
return (env ++ " This is Jerry.")
tomAndJerry :: Reader String String
tomAndJerry = do
t <- tom
j <- jerry
return (t ++ "\n" ++ j)
runJerryRun :: String
runJerryRun = (runReader tomAndJerry) "Who is this?"
tom::阅读器字符串
汤姆=做
env前两个函数都返回自己的读卡器monad实例。然后,您可以将它们组合在一起(在第三个函数中)
对于参数,让我们用IO
替换Reader
,并执行类似操作,这些函数都不接收任何参数:
getIntFromFile::IO Int
getIntFromFile=do
我认为丹尼尔·瓦格纳在评论中提到了一个重要的误解。Reader
是(包装)一个函数,因此它接受参数。鉴于此,我猜你的最后一个问题
我的读者monad是一种全球性的吗
有一个答案:是的,从某种意义上说,读者monad提供了一种通过链式计算传递不可变状态/环境的方法;所以它每次调用时(通过ask
)都会读取相同的值
在您的代码中,这意味着两个ask
s(或者相当于tom
和jerry
)都读取相同的环境,由字符串“这是谁?”
表示
嗯,通过去除do
s:
tom::阅读器字符串
汤姆=询问>>=\env->返回(env++“我是汤姆”)
jerry::读卡器字符串
jerry=询问>>=\env->返回(env++“我是jerry”)
tomAndJerry::读取器字符串
tomAndJerry=tom>>=\t->jerry>=\j->return(t++“\n”+++j)
这里的>=
需要一个返回单子的函数,但是你没有它,你有一个“普通”函数(例如\env->env++“This is Tom.”
),所以你必须使用return
将结果包装回单子。然后,而不是使用>=
和返回。f
,既然我们只需要在monad中应用一个函数,为什么不使用fmap f
这意味着我们可以通过使用tom
的Functor
和jerry
以及tomAndJerry
的Applicative
来进一步简化
tom::阅读器字符串
汤姆=fmap(++“我是汤姆”)问
jerry::读卡器字符串
jerry=fmap(++“我是jerry”)问
tomAndJerry::读取器字符串
汤姆杰里=(\t j->t++“\n+++j)汤姆杰里
tom
和jerry
都是ask
ing的环境,它们都对环境应用了一个函数。然后,tomAndJerry
只是通过二进制函数组合它们的一种方式,正如公认的答案所指出的那样
顺便说一下,语言服务器告诉我,询问
,它允许写
tom::阅读器字符串
汤姆=问(++“我是汤姆。”)
阅读器ra
与r->a
同构。因此,您关于“这些函数不接收任何参数”的断言在技术上是正确的,但并不能真正代表事实:此处显示的所有读取器
操作都接收一个字符串
参数。哦,因此,该函数中的返回实际上是在实例化读取器monad,我没有意识到我期望收到一些东西作为输出,一个返回,一种转换后的东西作为输出,现在对我来说是有意义的,因为IO非常清楚输入来自哪里,文件和stdin,但是在Reader中呢?它在内存中有一个神奇的对象,可以从中绑定和查找东西?@geckos输入是提供给runReader-someValueInTheReaderMonad
<代码>x