我猜,你得到的是從嘗試到foldr
到foldl'
簡單地切換錯誤:
myConcat xs ys = foldl' (:) ys xs
產生的誤差(用我的擁抱REPL):
ERROR - Type error in application
*** Expression : foldl' (:) xs ys
*** Term : (:)
*** Type : a -> [a] -> [a]
*** Does not match : [a] -> a -> [a]
在公告最後兩行(提供的類型和預期類型)[a]
和a
的位置處於相反的位置。這意味着我們需要一個類似於(:)
的函數,但它以相反的順序參數。
Haskell有一個功能,它爲我們做到這一點:flip
函數。基本上,flip
相當於
flip :: (a -> b -> c) -> (b -> a -> c)
flip f y x = f x y
即,flip
取二進制函數作爲參數,並返回原來的另一個二進制函數,其自變量被反轉(「翻轉」)。因此,儘管(:)
的類型爲a -> [a] -> [a]
,但我們看到flip (:)
的類型爲[a] -> a -> [a]
,因此它是foldl'
的參數的完美候選者。
使用flip
,我們現在有這樣的代碼:
myConcat xs ys = foldl' (flip (:)) ys xs
此結果與事實foldl'
的類型是(a -> b -> c) -> a -> [b] -> c
帶參數運行此[1..5]
和[6..10]
,我們得到的[5,4,3,2,1,6,7,8,9,10]
結果,這幾乎是我們想要的。唯一的問題是結果中第一個列表倒退。添加一個簡單的調用reverse
賦予我們的myConcat
最後定義:
myConcat xs ys = foldl' (flip (:)) ys (reverse xs)
縱觀這一過程顯示了經常出現的好東西之一,當寫Haskell代碼:當你碰到一個問題,您可以一次解決一個(小)步驟。當你已經有一個工作實現時,這是尤其如此,而你只是試圖編寫另一個實現。需要注意的是,如果您更改了實現的一部分(在這種情況下,將foldr
更改爲foldl'
),那麼其他許多其他必需的更改就會脫離類型定義。剩下的少數是可以很容易找到的糾正問題,無論是通過運行測試用例,還是通過查看所使用函數的確切性質。 PS:任何可以清理最後一行代碼的Haskell傢伙,都可以隨時這樣做。雖然它並不可怕,但我不覺得它很漂亮。不幸的是,我對Haskell不太瞭解。
您的帖子真實我幫助了我。感謝您的解釋:) – Adi 2011-06-17 12:54:07