我知道下面的“做”记号的“绑定”功能等同于getLine >>= \line -> putStrLn
转换一个“做”记号有两个以上的操作来使用绑定功能
do line <- getLine
putStrLn line
但是如何以下符号相当于绑定函数?
do line1 <- getLine
putStrLn "enter second line"
line2 <- getLine
return (line1,line2)
我知道下面的“做”记号的“绑定”功能等同于getLine >>= \line -> putStrLn
转换一个“做”记号有两个以上的操作来使用绑定功能
do line <- getLine
putStrLn line
但是如何以下符号相当于绑定函数?
do line1 <- getLine
putStrLn "enter second line"
line2 <- getLine
return (line1,line2)
我认为你正在试图看看如何绑定“putStrLn”的结果。答案是putStrLn的类型:
putStrLn :: String -> IO()
记住“()”是该单元型,它具有一个单一的值(也写作“()”)。所以你可以用完全相同的方式来绑定它。但既然你不使用它,你把它绑定到一个“不关心”值:
getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)
碰巧,已经有忽视的返回值,“>>”限定的操作。所以你可以重写这个为
getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)
我不知道你是否也试图了解如何绑定运算符是菊花链。看到这一点,让我把隐式支架和额外的压痕在上面的例子:
getLine >>= (\line1 ->
putStrLn "enter second line" >> (
getline >>= (\line2 ->
return (line1, line2))))
每个绑定运营商的价值链接到只剩下一个函数的权利。该函数由“do”子句中的所有其余行组成。因此,通过lambda(第一行中的“line1”)绑定的变量处于整个子句其余部分的范围内。
getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)
一般foo <- bar
变得bar >>= \foo ->
和baz
成为baz >>
(除非它是做块的最后一行,在这种情况下,它只是停留baz
)。
对于这个特定的例子中,你实际上可以通过使用组合程序从Control.Applicative
同时避免do
和>>=
:
module Main where
import Control.Applicative ((<$>), (<*>), (<*))
getInput :: IO (String, String)
getInput = (,) <$> getLine <* putStrLn "enter second line" <*> getLine
main = print =<< getInput
预期其中一期工程:
[email protected]% ./Main
hello
enter second line
world
("hello","world")
它看起来有点怪异的在第一,但在我看来,一旦你习惯了它,应用风格会感觉很自然。
我强烈建议您阅读Real-World haskell一书中的Desugaring of Do-blocks一章。它告诉你,你都错了。对于程序员来说,这是使用lambda的自然方式,但是使用函数实现do-block(如果发生模式加工失败)将调用相应monad的fail
实现。
例如,你的情况是这样的:
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
在这样的情况下,这可能是完全不相干的。但考虑一些涉及模式匹配的表达式。此外,您还可以使用这种效果对于一些特殊的东西,比如,你可以做这样的事情:
oddFunction :: Integral a => [a] -> [a]
oddFunctiond list = do
(True,y) <- zip (map odd list) list
return y
什么将这个功能呢?您可以阅读本声明作为处理列表元素的规则。第一个语句将列表的一个元素绑定到var y,但只有当y是奇数时才会这样。如果y是偶数,则会发生模式匹配失败,并调用fail
。在列表的单子实例中,fail
只是[]
。因此,该功能从列表中剥离所有偶数元素。
(我知道,oddFunction = filter odd
会做得更好,但是这只是一个例子)
第一个例子会更自然写作'函数getline >> = putStrLn'。那里的注释非常尴尬。 – Chuck 2010-09-14 17:04:42