2012-04-11 25 views
3

Ich versuche, alle Instanzen eines Elements in einer Liste mit Haskell zu löschen. Ich bekomme einen Fehler, den ich nicht wirklich verstehe. Kann mir jemand helfen und mich wissen lassen, ob ich das Richtige tue?Löschen Sie alle Instanzen aus der Liste

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

Welchen Fehler bekommen Sie? –

Antwort

9

Zunächst ist die Art Signatur fehlerhaft.

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

Eine Art Unterschrift hat die Form

name :: (Constraints) => type 

wo Constraints Typklassen beinhalten, wie (Ord a, Show a). In diesem Fall verwendet die Funktion (==), daher muss eine Einschränkung der Form vorliegen.

Dann stimmt die Funktionsdefinition nicht mit dem Typ Teil überein, Sie haben sie definiert, um ein Paar als Argument zu verwenden, während die Typ-Signatur das Gegenteil sagt (Ihre Definition ist nicht Curritiert, der Typ ist curried).

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

dann verwenden Sie (++) ein Element der Vorderseite einer Liste zu kleben, aber (++) verkettet zwei Listen, müssen Sie (:) hier.

Der einfachste Weg, um die Funktion definieren würde filter

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

aber wenn man sich die explizite Rekursion tun wollen benutzen,

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

Was, wenn ich wollte, dass dies auch an Zeichenketten anstatt nur an Zahlen funktioniert – cclerville

+5

Es gibt hier nichts, das Zahlen erwähnt, es funktioniert mit jedem Typ, der eine Instanz von 'Eq' ist, einschließlich' String', '[String]' und so weiter . Es hat den allgemeinsten Typ, den es haben kann, also funktioniert es für alles, für das es möglicherweise arbeiten kann. (Sie können die'Eq'-Bedingung umgehen, indem Sie einen Parameter '(a -> a -> Bool)' haben, der angibt, welche Werte als 'gleich' betrachtet werden sollen, die 'Eq'-Klasse stellt diese Funktion quasi als impliziten Parameter zur Verfügung .) –

+1

Sie haben Recht. Vielen Dank! :) – cclerville

3

Ich bin mir nicht sicher, was Sie mit den (a, [l]) vor den => zu tun versuchen, aber ich glaube es nicht für notwendig. Syntax dort ist normalerweise reserviert für die Angabe, welche Art a und l erfüllen sollte.

Auch Ihre Funktion benötigt zwei Argumente, a und [l], wie Sie später in der Funktionsdefinition angegeben haben. Ihre Implementierung der Funktion benötigt jedoch nur ein Argument, ein Tupel. Wie ich bereits erwähnt habe, dient das Tupel nur dazu, zu spezifizieren, welche Typen die Argumente sein sollen, und es kann kein Muster dafür gefunden werden.

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

Wenn Sie es mit filter schreiben wollte, können Sie immer den folgenden Code verwenden

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

ich eine sehr tatsächlich Liste Verständnis finden intuitive Notation für Probleme wie diese:

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

Es ist nicht schneller - beide sind 'O (n)'. Auch die Verkettung mehrerer Funktionen wie "Filter" ist immer noch "O (n)" wegen _Fusion_, z. 'Filter f. Karte f '.Filter f''' ist immer noch 'O (n)'. –

+0

Die Komplexität ist offensichtlich die gleiche, aber soweit ich ghc verstehe, wird der kompilierte Code schneller sein, da Listenkompressen in einfache Rekursionen aufgelöst werden, und Sie speichern somit den Aufruf zu filtern. es könnte von der Komplexität der Beschränkungen abhängen. – thrau

+2

Listencomprehensions sind eigentlich nur eine alternative Syntax für die Do-Notation, und so beginnt Ihr Verständnis zuerst mit 'list >> = \ a '-> wenn ein'/= a dann ein 'else []' zurückgibt. Danach führt das Optimierungsprogramm tatsächlich die Übersetzung in einfache Rekursionen durch, aber es macht es für die erzeugten Funktionen ebenso wie für alle anderen Funktionen, die _Fusion_ unterliegen. 'filter' und' map' unterliegen auch der Fusion, und deshalb sollte der erzeugte Compiler-Code mit Ihrem identisch sein. Sie können mit __ghc-core__ util experimentieren, Sie werden überrascht sein, was der Optimierer tatsächlich tun kann. –

Verwandte Themen