其實你在問題中給出的函數編譯得很好。您會得到,如果你遇到了什麼是不是你報的錯誤:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
| b == [] = []
| g == [] = []
| otherwise = (a, z) : myzip b g
有了一個明確的類型簽名話說任何類型a
和b
的列表myzip
作品。但您已使用b == []
和g == []
。平等運算符不是,只在類型爲Eq
類型的成員的類型上定義,因此您編寫的代碼與您提供的類型不匹配。
這就是錯誤信息非常直截了當的說法,但如果你只是在學習,還沒有開始輸入類,那麼它有點不清楚。
如果更改myzip
類型簽名說a
和b
需要是Eq
類型類的成員,那麼你給的代碼將工作:
myzip :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)]
或者,如果你離開類型簽名完全關閉(就像你在問題中所做的那樣),GHC實際上從你使用==
運算符的事實推斷出這種類型,並且代碼只是按原樣編譯。
然而,檢查列表是否爲空可以不使用==
運營商來完成,所以你可以寫myzip
,這樣它確實對任何類型的a
和b
操作。一種方法是使用null
功能:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:b) (z:g)
| null b = []
| null g = []
| otherwise = (a, z) : myzip b g
但更常見的方法是簡單地使用多個公式來定義myzip
,含底座的情況下匹配與模式[]
和到達假設主要情況列表是非空的:
myzip :: [a] -> [b] -> [(a, b)]
myzip (a:[]) _ = []
myzip _ (z:[]) = []
myzip (a:b) (z:g) = (a, z) : myzip b g
請注意,這種風格也明顯表明您的實現中存在一個錯誤。你扔掉最後的a
或z
,並且沒有時間列表完全空的情況!
當你的等式說myzip (a:b) (z:g)
和然後檢查b
和g
對空列表,它實際上是檢查錯誤的事情爲時已晚。您不需要檢查b
是否爲[]
,您需要檢查整個列表是否爲空。但是你已經認爲它不是空的,並將它分解成a:b
。這導致你的代碼(a)返回錯誤的結果,因爲它丟棄了它應該壓縮的最後一對元素,並且(b)當其中一個參數是空列表時產生錯誤。在列表
遞歸通常看上去更像是這樣的:
myzip :: [a] -> [b] -> [(a, b)]
myzip [] _ = []
myzip _ [] = []
myzip (a:b) (z:g) = (a, z) : myzip b g
這種行爲正確。
來源
2013-05-05 04:45:05
Ben
謝謝!我張貼了一個帖子,出去吃點快餐,然後回到一個寫得很好的,經過深思熟慮的迴應。互聯網是神奇的,它的人是神奇的。你很神奇! <3 <3 <3 – MYV 2013-05-05 05:13:52