2013-05-05 21 views
7

我有以下實施拉鍊功能的哈斯克爾Haskell的實現的「拉鍊」奇怪的錯誤

myzip (a:b) (z:g) 
    | b == [] = [] 
    | g == [] = [] 
    | otherwise = (a,z) : myzip b g 

當我把它加載到ghci中,我得到以下錯誤

No instance for (Eq b) 
    arising from a use of `==' 
In the expression: g == [] 
In a stmt of a pattern guard for 
       an equation for `myzip': 
    g == [] 
In an equation for `myzip': 
    myzip (a : b) (z : g) 
     | b == [] = [] 
     | g == [] = [] 
     | otherwise = (a, z) : myzip b g 

失敗,模塊加載:無。

我真的不知道爲什麼這不起作用。任何人都可以幫我嗎?

回答

14

其實你在問題中給出的函數編譯得很好。您得到,如果你遇到了什麼是不是你報的錯誤:

myzip :: [a] -> [b] -> [(a, b)] 
myzip (a:b) (z:g) 
    | b == [] = [] 
    | g == [] = [] 
    | otherwise = (a, z) : myzip b g 

有了一個明確的類型簽名話說任何類型ab的列表myzip作品。但您已使用b == []g == []。平等運算符不是,只在類型爲Eq類型的成員的類型上定義,因此您編寫的代碼與您提供的類型不匹配。

這就是錯誤信息非常直截了當的說法,但如果你只是在學習,還沒有開始輸入類,那麼它有點不清楚。

如果更改myzip類型簽名說ab需要是Eq類型類的成員,那麼你給的代碼將工作:

myzip :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)] 

或者,如果你離開類型簽名完全關閉(就像你在問題中所做的那樣),GHC實際上從你使用==運算符的事實推斷出這種類型,並且代碼只是按原樣編譯。

然而,檢查列表是否爲空可以不使用==運營商來完成,所以你可以寫myzip,這樣它確實對任何類型的ab操作。一種方法是使用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 

請注意,這種風格也明顯表明您的實現中存在一個錯誤。你扔掉最後的az,並且沒有時間列表完全空的情況!

當你的等式說myzip (a:b) (z:g)然後檢查bg對空列表,它實際上是檢查錯誤的事情爲時已晚。您不需要檢查b是否爲[],您需要檢查整個列表是否爲空。但是你已經認爲它不是空的,並將它分解成a:b。這導致你的代碼(a)返回錯誤的結果,因爲它丟棄了它應該壓縮的最後一對元素,並且(b)當其中一個參數是空列表時產生錯誤。在列表

遞歸通常看上去更像是這樣的:

myzip :: [a] -> [b] -> [(a, b)] 
myzip [] _ = [] 
myzip _ [] = [] 
myzip (a:b) (z:g) = (a, z) : myzip b g 

這種行爲正確。

+5

謝謝!我張貼了一個帖子,出去吃點快餐,然後回到一個寫得很好的,經過深思熟慮的迴應。互聯網是神奇的,它的人是神奇的。你很神奇! <3 <3 <3 – MYV 2013-05-05 05:13:52