2010-07-10 73 views
1

我是從博客的一個嘗試一些代碼段,我來到注意到下面的代碼爲什麼這不會引發任何類型的錯誤?

f :: Int -> [Int] 
f x = [1+x,2*x] 

test :: IO() 
test = putStrLn . show $ return 5 >>= f >>= f 

在執行我得到[7,12,11,20]。爲什麼第二個'f'函數調用不是拋出類型錯誤?這與List Monad有關嗎?

回答

4

讓我們問GHC什麼類型是一些子表達式。

> :t putStrLn . show 
putStrLn . show :: (Show a) => a -> IO() 

這的確如預期的那樣。

> :t return 5 >>= f >>= f 
return 5 >>= f >>= f :: [Int] 

我想我們預計,但它不能回答你的問題。接下來,對錶達如何解析此提醒:

> :i (>>=) 
class Monad m where 
    (>>=) :: m a -> (a -> m b) -> m b 
    ... 
infixl 1 >>= 

好了,它的左關聯的,所以表達(return 5 >>= f) >>= f

> :t return 5 >>= f 
return 5 >>= f :: [Int] 

比較這對上述類型簽名(>>=),我們可以觀察到兩件事情:

  • (>>=)第二個參數必須返回某種單子
  • (>>=)第一個參數必須是一個值在同一單子中

所以我們知道f必須有一個類型形狀這裏是,f的實際類型簽名是Int -> [Int]。因此,我們可以手工組合類型:

  • a = Int
  • b = Int
  • m = []

注意([] a)意味着同樣的事情[a]

所以monad確實是list monad。發生什麼了?

> return 5 :: ([] Int) 
[5] 
> [5] >>= f 
[6, 10] 
> ([5] >>= f) >>= f 
[7, 12, 11, 20] 
+0

感謝您的答案。現在我明白它是如何工作的。看起來有很多要了解單子 – jijesh 2010-07-11 04:11:47

6

這正是因爲列表是單子。你有

return 5 >>= f >>= f 

在列表單子,(>>=) = flip concatMap,所以這是一樣

concatMap f $ concatMap f $ return 5 

而且在列表單子,return x = [x],所以我們必須

concatMap f $ concatMap f [5] 

現在,concatMap g x = concat (map g x),所以我們可以擴展到

concat $ map f $ concat $ map f [5] 

,並評估其

concat $ map f $ concat $ [[6, 10]] 
concat $ map f $ [6, 10] 
concat $ [[7, 12], [11, 20]] 
[7, 12, 11, 20] 

這是否有意義?

+0

謝謝。我感到困惑與一個< - 返回5並讓a = 5 – jijesh 2010-07-11 05:10:25

相關問題