我知道以下“do”表示法的“绑定”功能相当于getLine >>= \line -> putStrLn
do line <- getLine
putStrLn line
但是以下符号如何等同于绑定函数?
do line1 <- getLine
putStrLn "enter second line"
line2 <- getLine
return (line1,line2)
答案 0 :(得分:16)
我认为你试图看看如何绑定“putStrLn”的结果。答案是putStrLn的类型:
putStrLn :: String -> IO ()
请记住,“()”是单位类型,它有一个值(也写成“()”)。所以你可以用完全相同的方式绑定它。但是既然你没有使用它,你将它绑定到“不关心”值:
getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)
实际上,已经定义了一个忽略返回值的运算符“&gt;&gt;”。所以你可以把它重写为
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”)在整个子句的其余部分的范围内。
答案 1 :(得分:7)
对于此特定示例,您可以使用do
中的组合器实际避免>>=
和Control.Applicative
:
module Main where
import Control.Applicative ((<$>), (<*>), (<*))
getInput :: IO (String, String)
getInput = (,) <$> getLine <* putStrLn "enter second line" <*> getLine
main = print =<< getInput
按预期工作:
travis@sidmouth% ./Main
hello
enter second line
world
("hello","world")
起初看起来有点奇怪,但在我看来,一旦你习惯了它,应用风格会非常自然。
答案 2 :(得分:3)
getLine >>= \line1 ->
putStrLn "enter second line" >>
getLine >>= \line2 ->
return (line1, line2)
通常foo <- bar
变为bar >>= \foo ->
而baz
变为baz >>
(除非它是do-block的最后一行,在这种情况下它只会baz
)。
答案 3 :(得分:3)
我强烈建议您阅读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
。在列表的monad实例中,fail
只是[]
。因此,该函数会从列表中删除所有偶数元素。
(我知道,oddFunction = filter odd
会做得更好,但这只是一个例子)