2009-01-10 20 views
6

ich ein Tutorial lese, die das folgende Beispiel verwendet (die ich etwas verallgemeinern werden):Bei der Destrukturierung von Tupeln in Haskell, wo können die Elemente verwendet werden?

f :: Foo -> (Int, Foo) 
... 
fList :: Foo -> [Int] 
fList foo = x : fList bar 
    where 
    (x, bar) = f foo 

Meine Frage liegt in der Tatsache, dass es scheint, dass Sie zu x und bar, namentlich beziehen, außerhalb das Tupel, wo sie erhalten werden. Dies scheint in anderen Sprachen wie eine destrukturierende Parameterliste zu funktionieren, wenn meine Vermutung richtig ist. (Mit anderen Worten, ich musste folgendes nicht tun :)

Bin ich richtig über dieses Verhalten? Ich habe es noch nie in den Tutorials/Büchern gesehen, die ich gelesen habe. Kann mir jemand mehr Infos zu dem Thema geben?

Bearbeiten: Kann irgendetwas (Listen, Arrays, etc.) in ähnlicher Weise destrukturiert werden, oder können Sie das nur mit Tupeln tun?

+1

Wenn Sie in diesem Tutorial eventuell nicht auf eine Erklärung des Mustervergleichs stoßen, möchten Sie vielleicht eine ausführlichere Erklärung von Haskell hinzufügen. Pattern Matching ist grundlegend und wichtig für die Sprache. –

Antwort

13

Ihre bearbeiten sehen, denke ich, was ist Ihr fragt Pattern matching.

Und um Ihre Frage zu beantworten: Ja, alles, was Sie konstruieren können, können Sie auch mit den Konstruktoren "dekonstruieren". Zum Beispiel, sind Sie wahrscheinlich mit dieser Form der Mustererkennung vertraut:

head :: [a] -> a 
head (x:xs) = x 
head []  = error "Can't take head of empty list" 

Allerdings gibt es mehr Orte, wo man Pattern-Matching, andere gültige Bezeichnungen sind verwenden können:

head xs = case xs of 
       (y:ys) -> y 
       []  -> error "Can't take head of empty list" 

head xs = let (y:ys) = xs 
      in y 

head xs = y 
    where 
    (y:ys) = xs 

Beachten Sie, dass die Die letzten beiden Beispiele unterscheiden sich etwas von den ersten, da sie unterschiedliche Fehlermeldungen ausgeben, wenn Sie sie mit einer leeren Liste aufrufen.


Obwohl diese Beispiele spezifisch für Listen sind, können Sie das gleiche mit anderen Datentypen tun, etwa so:

first :: (a, b) -> a 
first tuple = x 
    where 
    (x, y) = tuple 

second :: (a, b) -> b 
second tuple = let (x, y) = tuple 
       in y 

fromJust :: Maybe a -> a 
fromJust ma = x 
    where 
    (Just x) = ma 

Auch hier wird auch die letzte Funktion zum Absturz bringen, wenn Sie es mit Nothing nennen.

Zusammenfassend; Wenn Sie etwas mithilfe von Konstruktoren erstellen können (wie (:) und [] für Listen oder (,) für Tupel oder Nothing und Just für Maybe), können Sie dieselben Konstruktoren verwenden, um die Mustererkennung auf verschiedene Arten durchzuführen.

2

Habe ich Recht mit diesem Verhalten?

Ja. Die Namen existieren jedoch nur in dem Block, in dem Sie sie definiert haben. In Ihrem Fall bedeutet dies die logische Einheit, auf die Ihre where-Klausel angewendet wird, d. H. Der Ausdruck innerhalb von fList.

0

Ja, Sie haben Recht. In einer where-Klausel enthaltene Namen sind für die vollständige Deklaration vor der where-Klausel sichtbar. In Ihrem Fall sind diese Namen f und bar.

(Einer der harten Dinge über Haskell zu lernen ist, dass es nicht nur erlaubt, sondern häufig an Orten Variablen im Quellcode zu verwenden, die die Positionen voraus, wo diese Variablen definiert sind.)

Der Ort zum Lesen mehr über where-Klauseln ist in der Haskell 98 Report oder in einem der vielen feinen Tutorials zu finden unter haskell.org.

1

Ein anderer Weg, um es zu betrachten ist, dass Code wie dieser

x where x = 3 

entspricht in etwa

let x = 3 in x