2010-09-14 19 views
6

我知道下面的“做”记号的“绑定”功能等同于getLine >>= \line -> putStrLn转换一个“做”记号有两个以上的操作来使用绑定功能

do line <- getLine 
    putStrLn line 

但是如何以下符号相当于绑定函数?

do line1 <- getLine 
    putStrLn "enter second line" 
    line2 <- getLine 
    return (line1,line2) 
+4

第一个例子会更自然写作'函数getline >> = putStrLn'。那里的注释非常尴尬。 – Chuck 2010-09-14 17:04:42

回答

16

我认为你正在试图看看如何绑定“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”)绑定的变量处于整个子句其余部分的范围内。

3
getLine >>= \line1 -> 
putStrLn "enter second line" >> 
getLine >>= \line2 -> 
return (line1, line2) 

一般foo <- bar变得bar >>= \foo ->baz成为baz >>(除非它是做块的最后一行,在这种情况下,它只是停留baz)。

7

对于这个特定的例子中,你实际上可以通过使用组合程序从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") 

它看起来有点怪异的在第一,但在我看来,一旦你习惯了它,应用风格会感觉很自然。

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。在列表的单子实例中,fail只是[]。因此,该功能从列表中剥离所有偶数元素。

(我知道,oddFunction = filter odd会做得更好,但是这只是一个例子)

相关问题