Haskell:对'>> =`运算符的类型感到困惑

时间:2014-10-14 16:32:27

标签: haskell bind monads io-monad

我正在通过一些介绍性的Haskell材料,目前正在通过Monads。我从概念上理解>>=运算符的类型为:

(Monad m) => m a -> (a -> m b) -> m b

在这种情况下,我对以下代码的工作原理感到困惑,即为什么它不会导致类型不匹配:

main = getLine >>= \xs -> putStrLn xs

因为我们知道getLine :: IO String,所以我假设它可以与String -> IO String类型的函数“绑定”。但putStrLn的类型不同:putStrLn :: String -> IO ()

那么为什么Haskell允许我们将>>=与这两个函数一起使用?

3 个答案:

答案 0 :(得分:14)

让我们排列类型:

(>>=)    ::  m      a -> (     a ->  m  b) -> m b
getLine  :: IO String
putStrLn ::              (String -> IO ())

此处我们有m = IOa = Stringb = (),因此我们可以将这些内容替换为>>=类型的签名,以获得最终类型签名

(>>=) :: IO String -> (String -> IO ()) -> IO ()

答案 1 :(得分:5)

()是一个有效的类型(称为单位,请注意它只包含一个可能的非底值),在定义中将是b

a = Stringb = ()因此我们得到:

IO String -> (String -> IO ()) -> IO ()

答案 2 :(得分:4)

  

由于我们知道getLine :: IO String,因此我认为它可能会被绑定'具有String -> IO String类型的函数。

为什么你会这么想?再看一下类型签名:

(>>=) :: m a -> (a -> m b) -> m b

左边的内容是m a,右边的内容是m b。最特别是中间的位a -> m b,表示您传递给>>=的函数需要a并返回m b。它没有说它必须返回m a,它说它可以是m b,其中b是任意随机类型。它不必匹配a

在您的示例中,lambda函数采用String并返回IO ()。所以a = Stringb = ()。那很好。