2012-04-11 75 views
3

我試圖使用haskell刪除列表中的項目的所有實例。我收到一個我不太明白的錯誤。任何人都可以幫助我,讓我知道如果我做正確的事情?刪除列表中的所有實例

deleteAllInstances :: (a, [l]) => a -> [l] -> [l] 
deleteAllInstances (a, []) = [] 
deleteAllInstances (i, (x:xs)) 
    | i == x = tail 
    | otherwise = x ++ tail 
    where tail = deleteAllInstances i xs 
+2

你會得到哪個錯誤? – 2012-04-11 21:27:40

回答

9

首先,類型簽名的格式不正確。

deleteAllInstances :: (a, [l]) => a -> [l] -> [l] 

A型簽名的形式

name :: (Constraints) => type 

其中Constraints涉及類型類,像(Ord a, Show a)。在這種情況下,該功能使用(==),因此必須有Eq a的限制。

然後函數定義與類型部分不匹配,您定義它將一對作爲參數,而類型簽名另有說明(您的定義不確定,類型爲curried)。

deleteAllInstances (a, []) = [] 
deleteAllInstances (i, (x:xs)) 
    | i == x = tail 
    | otherwise = x ++ tail 
    where tail = deleteAllInstances i xs 

然後使用(++)一個元素膠水列表的前面,但(++)連接兩個列表,你需要(:)這裏。

定義函數是使用filter

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a xs = filter (/= a) xs 

,但如果你想自己做明確的遞歸最簡單的方法,

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a (x:xs) 
    | a == x = rest 
    | otherwise = x : rest 
     where 
     rest = deleteAllInstances a xs 
deleteAllInstances _ _ = [] 
+0

如果我想讓它也可以在字符串上工作而不僅僅是數字 – cclerville 2012-04-11 22:16:39

+5

這裏沒有提到數字,它適用於所有類型的'Eq'實例,包括'String','[String]'等等。它具有最普通的類型,因此它適用於可能適用的所有內容。 (你可以通過一個參數'(a - > a - > Bool)'去掉'Eq'約束,該參數說明哪些值應該被認爲是'相等的';'Eq'類提供的函數類似於隱式參數) – 2012-04-11 22:25:02

+1

你說得對。謝謝! :) – cclerville 2012-04-11 23:21:50

3

我不知道你想與(a, [l])=>之前做什麼,但我不認爲有必要。語法通常保留用於指定a和l應該滿足的類型。另外,你的函數有兩個參數,a[l],正如你稍後在函數定義中指定的那樣。然而,你的函數實現只需要一個參數,一個元組。正如我前面提到的,元組只能用來指定參數應該是什麼類型,並且不能與模式匹配。

deleteAllInstances :: a -> [l] -> [l] 
deleteAllInstances a [] = [] 
deleteAllInstances i (x:xs) 
    | i == x = rest 
    | otherwise = x : rest 
    where rest = deleteAllInstances i xs 

如果你想使用filter寫它,你總是可以使用下面的代碼

deleteAllInstances :: a -> [a] -> [a] 
deleteAllInstances a = filter (/=a) 
3

其實我覺得列表理解是一個非常直觀的符號表示這樣的問題:

deleteAllInstances :: Eq a => a -> [a] -> [a] 
deleteAllInstances a list = [x | x <- list, x /= a] 
+0

它不是更快 - 都是'O(n)'。甚至像'filter'這樣的鏈接多個函數仍然是'O(n)',因爲_Fusion_,例如'過濾器f。地圖f'。過濾器f''仍然是'O(n)'。 – 2013-06-16 08:45:34

+0

複雜性顯然是相同的,但據我瞭解ghc,編譯後的代碼會更快,因爲列表解析被解析爲純粹的遞歸,因此您將調用保存到過濾器。它可能取決於約束的複雜性。 – thrau 2013-06-16 14:06:46

+2

實際上,列表解析只是一個替代的符號語法,因此,如果一個'/ = a'然後返回一個'else []',你的理解首先解析爲'list >> = \ a' - >。在那之後,優化器確實做了平移遞歸的轉換,但是它對所生成的函數執行了這個操作,並且它會對任何受_Fusion_影響的其他函數執行。 'filter'和'map'也受到融合,這就是爲什麼生成的編譯器代碼應該與你的相同。你可以試驗__ghc-core__ util,你會驚訝於優化器實際上可以做什麼。 – 2013-06-16 14:24:45