2017-10-21 1 views
1

Ich versuche, eine verkettete Liste in Haskell mit dem folgenden Code zu drucken:Variable in ihrem Umfang nicht Fehler in der Funktion der Einsatz von Wachen

data List = Node {value:: Double, next:: List} 
      | Empty 

printList :: List -> String 
printList x | x == (Node v n) = show v ++ " " ++ printList n 
      | otherwise = show '_' 

Und die Kompilierungsfehler erhalten:

:load scratch.hs 
[1 of 1] Compiling Main    (scratch.hs, interpreted) 

scratch.hs:5:26: error: Variable not in scope: v :: Double 

scratch.hs:5:28: error: Variable not in scope: n :: List 

scratch.hs:5:38: error: Variable not in scope: v 

scratch.hs:5:53: error: Variable not in scope: n :: List 
Failed, modules loaded: none. 

Während ich Ich bin in der Lage, dasselbe zu tun, indem ich die Mustererkennung ohne Wächter benutze.

printList (Node v n) = show v ++ " " ++ printList n 
printList Empty = "" 

Was ist falsch mit dem ersten Code?

+0

In 'drucke (Node vn)', 'v' und' n' sind Argumente, aber in 'x == (Knoten vn)' sie sind zwei undefinierte Variablen. – ForceBru

+0

@ForceBru Gibt es eine Möglichkeit zu unterscheiden, welcher Datenkonstruktor x verwendet? –

Antwort

4

Sie tun nicht Mustererkennung mit einer Gleichheitsprüfung: Es ist möglich, dass zwei verschiedene Muster als gleich angesehen werden.

Also was Sie tun können, ist Definieren Sie ein Muster im Kopf einer der Klauseln Ihrer Funktion. Zum Beispiel:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList _ = show '_'

So, jetzt Haskell wird, für einen bestimmten List überprüfen, ob es mit dem Node v n Muster übereinstimmt, und wenn ja das Element auspacken und den Kopf zu v und dem Schwanz n zuweisen.

Wir können jedoch den Code noch verbessern. Normalerweise verwenden Sie keine Platzhalter, sondern alle möglichen Muster. Da, wenn Sie später die Definition von List verändern wollen, kann der Compiler Sie geben eine Warnung, dass Sie ein Muster vergessen:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList Empty = show '_'

Eine andere Sache, die wir verwendet "_" über show '_' verbessern können. Seit show '_' wird Zitate zum Inhalt hinzufügen. Zum Beispiel:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList Empty = "_"

Endlich können wir auch eine "cons" Konstruktion über das Anhängen mit einer Singleton-Liste verwenden:

printList :: List -> String 
printList (Node v n) = show v ++ ' ' : printList n 
printList Empty = "_"
+0

Aber ein Stück Code, den ich zuvor geschrieben habe, hat einen Funktionsparameter 'x', der mit der Datenkonstruktorzeile' Meter' verglichen wird. Hier ist der Code: 'data MetricUnit = Meter | Liter | Kilogramm Ableiten (Erscheinen, Eq) '' returnMetricSymbol x | x == Meter = "m" | x == Liter = "L" | x == Kilogramm = "kg" ' –

+1

@SafwanAhmad: Das liegt daran, dass (1) du' derving Eq' hinzugefügt hast und (2) hier nur nach Gleichheit sucht, du musst * den Konstruktor * nicht entpacken, es gibt keine Parameter in Ihrem Code, an denen Sie interessiert sind. –

+0

Ok, so verstehe ich, dass die Verwendung eines Data-Konstruktors innerhalb der Guard-Anweisung im Wesentlichen neue Variablen erzeugt. Wenn ich jedoch den gleichen Data-Konstruktor als Funktionsparameter verwende, wird ein Muster gefunden. Das bedeutet, dass mein Code im obigen Kommentar nur zufällig funktioniert, weil 'Meter' eine neue Variable erzeugt, die mit' x' verglichen wird und der Vergleich möglich ist, weil ich 'Eq' abgeleitet habe. Recht? –

Verwandte Themen