在这个 monad reader 示例中:
\nimport 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?"\nRun Code Online (Sandbox Code Playgroud)\n我们可以将 \xcb\x8bdo\xcb\x8b 符号读作
\ntomAndJerry = tom >>= \\t -> ...\nRun 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我没有尝试任何事情,因为它本身不是问题
\nReader 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 + y或f 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。
| 归档时间: |
|
| 查看次数: |
132 次 |
| 最近记录: |