2016-05-01 2 views
1

Unten ist ein Code, der von der Antwort auf another stack overflow question kommt. Es ist schon einige Wochen her, dass ich angefangen habe, Haskell zu studieren, und ich musste dieser besonderen Syntax noch begegnen, und ich kann nirgendwo eine Erklärung finden, nicht einmal eine Definition dafür. So , der Code:Haskell, Monad, Definition der Bindung und seltsame Mustererkennung auf einem Ausgabewert?

data Pair a = P a a 

instance Functor Pair where 
    fmap f (P x y) = P (f x) (f y) 

instance Monad Pair where 
    return x = P x x 
    P a b >>= f = P x y 
    where P x _ = f a 
      P _ y = f b 

verbrachte ich die letzte halbe Stunde versucht, den Sinn des Lebens zu verstehen, oder wenn etwas kannte ich schon die Definition dieses bind (>> =) Verfahren erläutert. GHCI lud es ohne Ärger ein (naja, es verlangte eine anwendbare Instanz, aber anders als das), also muss es sehr erlaubt sein, auch wenn ich den Anfang davon noch nicht verstanden habe.

Was bedeutet eine Definition, die durch Mustererkennung eines bereits definierten Datenkonstruktors aussieht? Was sind x und y, woher kommen sie?

Danke an alle, die darauf antworten. Und wenn jemand eine gute Idee für einen guten, spezifischen Titel zu dieser Frage hat - vorausgesetzt, dass ich die sehr syntaktische Bedeutung nicht wirklich verstehe, habe ich Schwierigkeiten, eine solche zu finden.


@leftaroundabout gab mir die Informationen, die ich brauchte, das war, dass das Stück Code

P x y 
    where P x _ = f a 
     P _ y = f b 

eine Form von Pattern-Matching des "Value-Unboxing" Typ war, anstatt die case of ähnlich wie auswahlorientiert. Ich wurde durch das Vorhandensein des _ Muster verblüfft, und so sah ich die oben genannten zwei Muster-Matchings nicht, wie sie waren, das heißt, wie die Definitionen von x dann y, weil es in einer Weise gemacht wurde, die ich nie erlebt hatte Vor.

Ich wusste, dass wir so etwas schreiben könnten:

f :: foo -> (Int, Int) 
... 
i = let (a,b) = f x 
    in a + b 

aber ich wusste nicht, dass wir in diesen Fällen von „value-Unboxing“ verwenden könnten (hier a und b zum Beispiel, oder x und y in dem Code, der mich abhörte), das volle Ausmaß der Möglichkeiten im Muster-Matching, das heißt, zumindest Definitionen, die _ verwenden, um die Teile zu isolieren, die wir nicht wollen, die Werte, die wir nicht an irgendwelche binden wollen "Etikette".

Kurz gesagt ich nicht, dass in dem obigen Beispiel nicht kannte, diese Gleichung

P x _ = f a 

eigentlich die Definition von x durch Pattern-Matching auf dem Ergebnis der (f a) war, so dass es in der Tat absolut gleichwertig war zu

wurde
x = g (f a) 
    where g (P t _) = t 

ich dachte, es war die Definition der bereits definierten Daten Konstruktor P stecken.

Antwort

4

Es gibt keine “ bestimmte Syntax ” hier, nur eine normale Mustererkennung. Der Code entspricht

pFst, pSnd :: Pair a -> a 
pFst (Pair x _) = x 
pSnd (Pair _ y) = y 

instance Monad Pair where 
    return x = P x x 
    P a b >>= f = P x y 
    where x = pFst $ f a 
      y = pSnd $ f b 

Wenn Sie Inline-pFst und pSnd, sehen Sie, dass diese direkt auf die ursprüngliche Definition führt.

Wenn Sie nicht überzeugt sind, bedenken, dass (nicht rekursiv) where Bindungen können mit Lambda-Abstraktionen ersetzt werden:

P a b >>= f = (\(Pair x _) (Pair _ y) -> P x y) 
        (f a)  (f b) 

Offensichtlich konnte das Lambda genausogut als benannte lokale Funktion geschrieben werden:

P a b >>= f = pFstAndPSnd (f a) (f b) 
    where pFstAndPSnd (Pair x _) (Pair _ y) = P x y 

Vielleicht wäre es verwirrend gewesen weniger, wenn Sie den Code gesehen hatte, wie es für gewöhnliche Tupeln aussehen:

(>>=) :: (c,c) -> (c -> (d,d)) -> (d,d) 
(a,b) >>= f = (x,y) 
    where (x,_) = f a 
     (_,y) = f b 

Dies ist offensichtlich& Dolch; definiert den (,) -Konstruktor in keiner Weise neu, sondern verwendet ihn nur zur Musterübereinstimmung mit Tupelergebnissen einer Funktion.


& dolch; Nun, ok, vielleicht ist es nicht , dass offensichtlich ist, zu sehen, wie Sie auch Dinge wie let 1+2=4 in 1+2 tun können, und erhalten 4 als Ergebnis.

+0

Nun, wenn ich es richtig übersetzen, bedeutet dies, dass offenbar kann man Muster-Match in umgekehrter , Teile eines Musters aus Variablen definieren, die, na ja, vom selben Muster sind, also könnte ich anscheinend schreiben: 'let (a, _) = (1,2); (_, b) = (3,4) in (a, b) == (1,4) '. Diese Fähigkeit, Werte durch sukzessive "partielle" Musterübereinstimmung zu definieren, indem Bits von anderen Variablen genommen werden, ist etwas, das ich einfach ignoriert habe. Ich kannte es ohne '_', grundsätzlich, außer natürlich bei der Definition von Funktionen, aber implizit ist es hier völlig anders, findest du nicht? – icelake

+0

Übrigens haben Sie 'pFst (Pair _ y) = y 'geschrieben, waren aber Opfer des Copy-Paste Hex, wie es' pSnd' hätte sein sollen. Und danke, natürlich. Ich habe versucht, meinen vorherigen Kommentar zu bearbeiten, aber er wurde abgelehnt. – icelake

+0

Ich bin neu bei SOverflow, muss ich etwas Besonderes machen, jetzt wurde es gelöst? – icelake

2

gut P ist in der Tat der Konstruktor für die Pair so a und b das erste und das zweite Element dieses (ein wenig seltsam) Paar sein (wenn Sie x = P 1 2 sagen ein x >>= f hier tun dann a = 1 und b = 2 - es ist genau Mustervergleich

Meine Vermutung ist, dass Sie Probleme mit der Definition der Funktion haben, wenn es hilft Ihnen, es als schreiben konnte.

(>>=) (P a b) f = P x y 
    where ... 

zu

siehe: so wie Sie können uns der Bediener zwischen Argumente so können Sie es definieren es

+0

Es war nicht genau dieser Teil, den ich nicht verstanden habe, aber der Teil, den du ellipse-d, aka der Teil, wo 'P x y 'durch" umgekehrte "Muster-Übereinstimmung definiert ist. Ich meine das natürlich in meiner Terminologie; aka der, der die linke Seite füllen soll, indem er Dinge von der rechten Seite wie ein Spiegel nimmt (wie in der Do-Notation Monad "Entkapselung", vage gesprochen), anstatt die rechte Seite in Bezug auf die linke Seite der '=' Zeichen, wie für Funktionsdefinitionen, und 'Fall von' Mustervergleich, in diesem Fall ist es natürlich ein' -> 'anstelle von' = '. – icelake

+0

es ist nicht * definiert * - es ist nur was * pattern-matching * ist - während der Definition der Funktion '(>> =)' Sie pattern-passen das erste Argument zu 'P ab' und da' Paar'nur diesen einen Konstruktor hat das wird alles fangen (also keine Notwendigkeit, einen anderen zu haben) - das hättest du aus der Art und Weise sehen sollen, wie du mit Listen in Funktion arbeitest (wo du normalerweise ein Muster/Case 'f [] = ...' und eins 'f hast (x: xs) = ... '- wieder eins für jeden Konstruktor einer Liste – Carsten

+0

natürlich kann man das auch mit einem 'case ... of'-Konstrukt machen - aber es liest sich viel schöner auf diese Weise, stimmst du nicht zu ? – Carsten