函数>>=的多态性

Haskell中一些函数可以作用在多种类型上。

例如:

ghci> length [1, 2]

2

length :: [Int] -> Int


ghci> length ["a", "b", "c"]

3

length :: [String] -> Int


我们看length的类型,

length :: [a] -> Int

它类型签名中,包含类型变量,类型变量可以具体化为任意类型。


像这样的函数,称为多态函数。


函数>>=

函数>>=定义在Monad类型类中,

class Monad m where

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


其中,m是Monad类型类的实例类型,它的kind是* -> *,

:k m = * -> *

类型m a是一个具体类型,该类型的值称为monad value。


我们看到,在m确定的情况下,>>=的类型签名中仍然包含类型变量。

因此,对Monad类型类的某个实例来说,

>>=可以操作相同m类型但是不同a类型的monad value :: m a。


IO monad

以Monad类型类的实例IO为例,对于IO来说,IO monad value称为IO action。

main = do

    putStrLn "Please input: "

    inpStr <- getLine

    putStrLn $ "Hello " ++ inpStr


其中,

putStrLn :: String -> IO ( )

getLine :: IO String


我们来分析一下这3个IO action的类型,

putStrLn "Please input: " :: IO ( )

getLine :: IO String

putStrLn $ "Hello " ++ inpStr :: IO ( )


它们的具体类型都是m a,

m相同,m = IO。而a不同,分别是( ),String,( )。


在do notation中,如果某一行我们没有使用<-为monad value绑定值,

就相当于使用了函数>>,表示不需要这个绑定值。

(>>) :: x >> y = x >>= \ _ -> y


这样的话,我们就可以将main函数还原成>>和>>=的串联形式了,

putStrLn "Please input: " >> getLine >>= -> putStrLn $ "Hello " ++ inpStr

= putStrLn "Please input: " >>= \ _ -> getLine >>= -> putStrLn $ "Hello " ++ inpStr

= putStrLn "Please input: " >>= ( \ _ -> getLine >>= ( -> putStrLn $ "Hello " ++ inpStr ) )


类型不同的>>=同时出现

对于第一个>>=,我们能推断出它的大概类型,

>>= :: IO ( ) -> (( ) -> IO ?) -> IO ?

其中“?”表示尚未确定的类型。


而第二个>>=的类型,可以完全确定下来。

getLine >>= -> putStrLn $ "Hello " ++ inpStr

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


那么,第一个>>=的类型也就可以完全确定下来了,

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


由此可见,

第一个>>= :: IO ( ) -> (( ) -> IO ( )) -> IO ( )

第二个>>= :: IO String -> (String -> IO ( )) -> IO ( )

两个>>=的类型不同,它们同时出现了。


结语

do notation是>>和>>=串联形式的语法糖,IO action是 IO monad value,因此可以使用它。

认为do notation中每行的monad value类型必须相同,是不正确的。

事实上,他们的类型是m a,m是相同的,而a可以不同。


相似的,Functor和Applicative类型类也定义了一些多态函数。


此外,对于IO类型,《Programming in Haskell》P88说的最清楚

type IO a = World -> (a, World)


World类型的值表示环境的当前状态。

World -> (a, World)类型的值是一个函数,

它接受环境状态作为参数,返回一个a类型的值,并影响了环境状态。