2011-04-02 26 views
14

這些是我在Haskell的第一次探索,所以請原諒我,如果它應該是明顯的。撰寫concat和map來獲取concatMap:爲什麼f?

我一直在和哈斯克爾一起玩,使用我自己的列表類型(典型的缺點)篩選教程99 questions on HaskellWiki。我繼續添加了「顯而易見」的功能,並且盡力使它們儘可能簡潔(儘可能使用免註釋符號)

第12個問題是關於解碼運行長度編碼列表,那就是:

> decode [Multiple 5 'a', Single 'b', Multiple 2 'c'] 
"aaaaabcc" 

我想過使用map每個元素進行解碼,然後concat結果(感謝谷歌在此),終於記起我曾見過類似的東西在我的讀數,這GHCI很快證實concatMap

> :t map 
map :: (a -> b) -> [a] -> [b] 
> :t concat 
concat :: [[a]] -> [a] 
> :t concatMap 
concatMap :: (a -> [b]) -> [a] -> [b] 

它看起來像這將是顯而易見的重新實現concatMap

concatMap :: (a -> [b]) -> [a] -> [b] 
concatMap = concat . map 

除GHCI頗爲抱怨:

List.hs:110:15: 
    Couldn't match expected type `[a] -> [b]' 
       with actual type `[a0]' 
    Expected type: [[a0]] -> [a] -> [b] 
     Actual type: [[a0]] -> [[a0]] 
    In the first argument of `(.)', namely `concat' 
    In the expression: concat . map 

我想不出來,所以我擡起頭,在網絡上,和Prelude中引用的定義其實是:

concatMap f = concat . map f 

我不太明白爲什麼這個f是必須的,因爲它的類型顯然是a -> [b]按照簽名規定...

那麼爲什麼f這裏需要?

回答

15

與標準的定義出發,

concat . map f 
≡ concat . (map f) 
≡ \x -> concat ((map f) x) 

你的第一個定義,爲您提供:

(concat . map) f 
≡ (\x -> concat (map x)) f 
≡ concat (map f) 

不類型檢查,因爲(map f) :: [a] -> [b],而concat需要[[a]],列出清單。

請注意問題中顯示的特定錯誤消息沒有描述上述類型檢查失敗。給定的消息來自聲明返回類型concatMap[a] -> [b],這與[a0]不一致,返回類型爲concat。如果你省略類型簽名,響應是:

 
    Couldn't match type ‘[a1] -> [b]’ with ‘[[a]]’ 
    Expected type: (a1 -> b) -> [[a]] 
     Actual type: (a1 -> b) -> [a1] -> [b] 
    Relevant bindings include 
     concatMap :: (a1 -> b) -> [a] (bound at :49:5) 
    Probable cause: ‘map’ is applied to too few arguments 
    In the second argument of ‘(.)’, namely ‘map’ 
    In the expression: concat . map 

這裏,協調的map與參數類型的concat返回類型時出現錯誤類型。事實證明,這種情況對於調試更有用,因爲它包含爲什麼類型檢查失敗的提示。

+1

啊!說'''右邊的函數應該期待一個單一的論證是否公平? (在咖喱之前,不是2個「地圖」?)另外,是否有一些技巧以點自由風格寫出來? – 2011-04-02 17:40:16

+1

@Matthiew Haskell中的每個函數都接受一個參數。例如,'map'接受一個函數並返回一個'g = map f'函數,該函數接受一個列表並返回一個元素。另外,請記住一件重要的事情:功能應用程序綁定比任何運算符都更緊密,它可以幫助您理清事情的真相。我不知道如何免費寫這個觀點。 – adamax 2011-04-02 17:46:33

+0

這絕對是一個奇怪的旅程,我正在着手:)'replicateList :: Int - > List a - > List a'(Problem 15,changed)可以寫成point'free作爲'replicateList = concatMap。複製'和兩個參數傳遞,沒有類型檢查問題。 – 2011-04-02 17:53:21