2015-06-18 45 views
0

考慮以下IO代碼:IO單子例

ghci> let x = return 100 :: IO Int 

ghci> :t do { a <- x; print a; return 500 } 
do { a <- x; print a; return 500 } :: Num b => IO b 

我的做記號/綁定的是,下面的簽名將被由編譯器執行的理解:

ghci> :t (>>=) 
(>>=) :: Monad m => m a -> (a -> m b) -> m b 

在上述例子中,我的理解是:

  • x有型號IO Int
  • print a具有類型IO()
  • return 500的類型爲Num b => IO b

這在我看來,IO()不符合的類型,Num b => IO b。據我所知,IO Int不符合Num b => IO b

如果這個觀察是有效的,那麼爲什麼這個代碼編譯?每行必須不爲>>=,符合m b,其中m等於IO,b等於Num b => b

+1

爲什麼'IO()'需要堅持類型?爲什麼不應該'IO Int'符合約束?請注意,do'block的desugared版本使用>> >> ='__and__'>>'。還要注意,中間類型對於這裏的結果類型並不重要,例如, 'f = const 3。單詞。儘管'words'的類型爲'String - > [String]',但是'show'的類型是'(顯示a,數字b)=> a - > b'「。 – Zeta

回答

3

您將desugars發佈到以下代碼中。

x >>= (\a -> 
print a >> 
return 500) 

或者向外擴展的(>>)

x  >>= (\a -> 
print a >>= (\_ -> 
return 500)) 

然後定義,你可以看到,在不同的調用(>>=),類型ab不一定相同。說(>>=) :: Monad m => m a -> (a -> m b) -> m b

  • 在第一次調用

    x具有類型IO Int\a -> print a >>= (\_ -> return 500)的類型爲Num c => Int -> IO c,所以在我們的類型簽名a(>>=)Int,而bc(與Num限制)。

  • 在第二次調用

    print a有類型IO(),並且的類型是Num c =>() -> IO c所以在我們的類型簽名a(>>=)()(該()部分從嘗試匹配的(>>=)簽名推斷),以及bc(仍與Num限制)。

1

do { a <- x; print a; return 500 }相當於(return 100 :: Int) >>= print >> return 500

>>的簽名是(>>) :: Monad m => m a -> m b -> m b,它與所看到的同步。