do 代码块实际上是把操作连接在一起的快捷记号。有两个运算符可以用来代替 do 代码块: >> 和 >>= 。在 ghci 看一下它们的类型:
ghci> :type (>>)
(>>) :: (Monad m) => m a -> m b -> m b
ghci> :type (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
>> 运算符把两个操作串联在一起:第一个操作先运行,然后是第二个。运算符的计算的结果是第二个操作的结果,第一个操作的结果被丢弃了。这和在 do 代码块中只有一行是类似的。你可能会写 putStrLn "line 1" >> putStrLn "line 2" 来测试这一点。它会打印出两行,把第一个 putStrLn 的结果丢掉了,值提供第二个操作的结果。
>>= 运算符运行一个操作,然后把它的结果传递给一个返回操作的函数。那样第二个操作可以同样运行,而且整个表达式的结果就是第二个操作的结果。例如,你写 getLine >>= putStrLn ,这会从键盘读取一行,然后显示出来。
让我们重写例子中的一个,不用 do 代码快。还记得这一章开头的这个例子吗?
-- file: ch07/basicio.hs
main = do
putStrLn "Greetings! What is your name?"
inpStr <- getLine
putStrLn $ "Welcome to Haskell, " ++ inpStr ++ "!"
我们不用 do 代码块来重写它:
-- file: ch07/basicio-nodo.hs
main =
putStrLn "Greetings! What is your name?" >>
getLine >>=
(\inpStr -> putStrLn $ "Welcome to Haskell, " ++ inpStr ++ "!")
你定义 do 代码块的时候,Haskell编译器内部会把它翻译成像这样。