我是從博客的一個嘗試一些代碼段,我來到注意到下面的代碼爲什麼這不會引發任何類型的錯誤?
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有關嗎?
我是從博客的一個嘗試一些代碼段,我來到注意到下面的代碼爲什麼這不會引發任何類型的錯誤?
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有關嗎?
讓我們問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]
這正是因爲列表是單子。你有
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]
這是否有意義?
謝謝。我感到困惑與一個< - 返回5並讓a = 5 – jijesh 2010-07-11 05:10:25
感謝您的答案。現在我明白它是如何工作的。看起來有很多要了解單子 – jijesh 2010-07-11 04:11:47