Haskell 的读者 Monad。读者作为参数传递到哪里?

Maf*_*edo 3 monads haskell

在这个 monad reader 示例中:

\n
import Control.Monad.Reader\n\ntom :: Reader String String\ntom = do\n    env <- ask -- gives you the environment which in this case is a String\n    return (env ++ " This is Tom.")\n\njerry :: Reader String String\njerry = do\n  env <- ask\n  return (env ++ " This is Jerry.")\n\ntomAndJerry :: Reader String String\ntomAndJerry = do\n    t <- tom\n    j <- jerry\n    return (t ++ "\\n" ++ j)\n\nrunJerryRun :: String\nrunJerryRun = (runReader tomAndJerry) "Who is this?"\n
Run Code Online (Sandbox Code Playgroud)\n

我们可以将 \xcb\x8bdo\xcb\x8b 符号读作

\n
tomAndJerry = tom >>= \\t -> ...\n
Run Code Online (Sandbox Code Playgroud)\n

最终你会得到一个字符串。好吧,所以,基本上 \xcb\x8b(runReader tomAndJerry) “这是谁?”\xcb\x8b 是一个阅读器,这样 \xcb\x8bask\xcb\x8b 给出 \xcb\x8b 这是谁?\xcb\x8b。但是,\xcb\x8btom\xcb\x8b 没有参数名称。请问如何才能运行?

\n

我可以将 \xcb\x8btom :: Reader String String\xcb\x8b 视为类似 C++ 泛型的东西,其中 \xcb\x8bReader\xcb\x8b 在编译时绑定到某个静态类,它总是生成“这是谁?” 你打电话问的时候就可以了吗?因为据我所知, \xcb\x8bask\xcb\x8b 是需要 \xcb\x8bReader String String\xcb\x8b 的东西,并且它没有明确地将其作为参数获取到任何地方。

\n

我知道它以某种方式获取上下文,但我对它在语言本身中如何发生很感兴趣。

\n

我没有尝试任何事情,因为它本身不是问题

\n

Dan*_*ner 9

Reader r a实际上,类型的东西不是类型的值a,而是类型的函数r -> a,它接受r环境并产生类型的值a。看看如果我在您的代码中进行这个简单的替换,您的问题会消失多少:

-- skip all imports, so we can use our own ask implementation

ask :: String -> String
ask s = s

tom :: String -> String
tom = do
    env <- ask -- gives you the environment which in this case is a String
    return (env ++ " This is Tom.")

jerry :: String -> String
jerry = do
  env <- ask
  return (env ++ " This is Jerry.")

tomAndJerry :: String -> String
tomAndJerry = do
    t <- tom
    j <- jerry
    return (t ++ "\n" ++ j)
Run Code Online (Sandbox Code Playgroud)

它的环境从哪里ask获得?嗯,它是一个函数,它以环境作为参数,就是这样!与 相同tom:它将其环境作为参数传递给它。

好吧,您可能会说,但看起来tom = do {- ... -}不像一个带有参数的函数。毕竟,标志左边没有任何争议!=

你说得对。对于传统的命令式程序员来说,它看起来不像一个函数。尽管如此,确实如此。别担心...随着时间的推移你会习惯的!举一个非常愚蠢的例子:

f = (+)
Run Code Online (Sandbox Code Playgroud)

虽然这看起来不像一个函数(它的符号左侧没有参数=),但它确实是一个函数。它的功能与原样完全相同(+)。非常相似的定义f x y = x + yf x y = (+) x y,看起来更像是一个函数,但含义几乎完全相同。一个稍微不那么愚蠢的例子:

g = if somethingComplicated then (+) else (*)
Run Code Online (Sandbox Code Playgroud)

函数只是可以传递、存储在变量中、作为复杂计算的结果返回等的简单对象。它们并不总是需要将其参数命名为函数!

现在让我们稍微浏览一下您的帖子。

好的,所以,基本上(runReader tomAndJerry) "Who is this?"是一个这样的读者,ask给出了Who is this?

我不喜欢这个措辞。那只是tomAndJerry一个读者;更完整的短语(runReader tomAndJerry) "Who is this?"是 a String,而不是读者。

但是,tom没有参数名称。怎么ask能跑?

没有任何命名参数,但仍然有一个参数。

我是否可以将其视为tom :: Reader String String类似于 C++ 泛型的东西,在Reader编译时绑定到某个静态类,"Who is this?"当您对其调用时总是会生成该静态类?

当然不。ask不是一个可以传递Reader参数的东西;它Reader本身就已经是一个行动了。你不能ask打电话tom。您可以将其视为tom :: Reader String String类似的东西tom :: String -> String。如果您愿意的话,您也可以认为可以在实施过程中使用ask类似的东西(但没有义务)。ask :: String -> Stringtom

因为据我所知,ask是需要 aReader String String并且没有明确地将其作为参数的任何地方。

不,请参阅上一点。ask a Reader String String,不需要 1。