jij*_*esh 6 monads haskell ghc
我知道以下"do"表示法的"绑定"功能相当于 getLine >>= \line -> putStrLn
do line <- getLine
putStrLn line
Run Code Online (Sandbox Code Playgroud)
但是以下符号如何等同于绑定函数?
do line1 <- getLine
putStrLn "enter second line"
line2 <- getLine
return (line1,line2)
Run Code Online (Sandbox Code Playgroud)
Pau*_*son 16
我认为你试图看看如何绑定"putStrLn"的结果.答案是putStrLn的类型:
putStrLn :: String -> IO ()
Run Code Online (Sandbox Code Playgroud)
请记住,"()"是单位类型,它具有单个值(也写为"()").所以你可以用完全相同的方式绑定它.但是既然你没有使用它,你将它绑定到"不关心"值:
getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)
Run Code Online (Sandbox Code Playgroud)
实际上,已经定义了一个忽略返回值">>"的运算符.所以你可以把它重写为
getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)
Run Code Online (Sandbox Code Playgroud)
我不确定你是否也试图理解绑定运算符是如何菊花链式的.为了看到这个,让我在上面的例子中加上隐式括号和额外的缩进:
getLine >>= (\line1 ->
putStrLn "enter second line" >> (
getline >>= (\line2 ->
return (line1, line2))))
Run Code Online (Sandbox Code Playgroud)
每个绑定操作符使用右侧的函数将值链接到左侧.该函数由"do"子句中的所有其余行组成.因此,通过lambda绑定的变量(第一行中的"line1")在整个子句的整个范围内.
对于这个具体的例子实际上你可以同时避免do和>>=利用组合子来自Control.Applicative:
module Main where
import Control.Applicative ((<$>), (<*>), (<*))
getInput :: IO (String, String)
getInput = (,) <$> getLine <* putStrLn "enter second line" <*> getLine
main = print =<< getInput
Run Code Online (Sandbox Code Playgroud)
哪个按预期工作:
travis@sidmouth% ./Main
hello
enter second line
world
("hello","world")
Run Code Online (Sandbox Code Playgroud)
起初看起来有点奇怪,但在我看来,一旦你习惯它,应用风格会很自然.
我强烈建议您阅读Real-World haskell 一书中的Desugaring of Do-blocks一章。它告诉你,你都错了。对于程序员来说,这是使用 lambda 的自然方式,但是 do-block 是使用函数实现的,如果发生模式处理失败,将调用fail相应 monad的实现。
例如,你的情况是这样的:
let f x =
putStrLn "enter second line" >>
let g y = return (x,y)
g _ = fail "Pattern mismatched"
in getLine >>= g
f _ = fail "Pattern mismatched"
in getLine >>= f
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这可能完全无关紧要。但是考虑一些涉及模式匹配的表达式。此外,您可以将此效果用于一些特殊的东西,例如,您可以执行以下操作:
oddFunction :: Integral a => [a] -> [a]
oddFunctiond list = do
(True,y) <- zip (map odd list) list
return y
Run Code Online (Sandbox Code Playgroud)
这个函数会做什么?您可以将此语句视为处理列表元素的规则。第一条语句将列表的一个元素绑定到 var y,但前提是 y 是奇数。如果 y 是偶数,则发生模式匹配失败fail并将被调用。在 Lists 的 monad 实例中,fail只是[]. 因此,该函数从列表中删除所有偶数元素。
(我知道,oddFunction = filter odd这样做会更好,但这只是一个例子)
getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)
Run Code Online (Sandbox Code Playgroud)
通常foo <- bar变成bar >>= \foo ->和baz变成baz >>(除非它是 do-block 的最后一行,在这种情况下它只是停留baz)。