2016-03-25 2 views
1

ich das Reich der Racket Buch lese, und Seite 175, ich in der Tat sehen diesen Code:Schläger: Pattern-Matching-Funktion Parameter

(struct dice-world (src board gt)) 
(struct game (board player moves)) 

(define (no-more-moves-in-world? w) 
    (define tree (dice-world-gt w)) 
    (define board (dice-world-board w)) 
    (define player (game-player tree)) 
    player) 

Die Funktion aus dem Buch gibt nicht die Spieler, aber alles bis diese Zeile wie im Buch steht. Für mich schreit dies nach der Notwendigkeit eines Mustervergleichs!

Und in der Tat, das funktioniert gut und ist deutlich lesbar und deutlich zu mir:

(define (no-more-moves+? w) 
    (match w 
    [(dice-world _ board (game _ player _)) player])) 

jedoch hier noch wir überhaupt die Variable w ohne Grund nennen. Ich möchte Mustererkennung auf die Funktionsparameter direkt zu können, wie diese (ungültige Syntax):

(define (no-more-moves2? (dice-world _ board (game _ player _))) 
    player) 

Aus meiner bisher Googeln scheint dies unmöglich? Das klingt unglaublich für mich? Das ist wahrscheinlich durch einige Makrotricks möglich, aber ich bin wirklich überrascht, dass es nicht die Standardmethode wäre, diesen Code aus dem Buch zu schreiben. Da ich ein Anfängerbuch bin, dachte ich, dass Mustererkennung später eingeführt wird, aber ich finde es überhaupt nicht im Index?

Auch wenn die Antwort ist, dass es nicht möglich/nicht idiomatisch ist, frage ich mich, ob es das gleiche mit anderen Lisps auch ist?

Antwort

3

Die gewünschte Form ist im Racket match-plus package, under the name define/match* erhältlich. Haftungsausschluss: Es ist mein Paket. Der folgende Code sollte funktionieren das Modul mit:

(require match-plus) 

(define/match* (no-more-moves2? (dice-world _ board (game _ player _))) 
    player) 

das Paket zu installieren, verwenden Sie DrRacket-Package Manager GUI oder den folgenden Befehl ausführen:

raco pkg install match-plus 

Ich denke, die Gründe für diese nicht in Clamens enthalten ist, wie John Clements erwähnt: Wenn die Musterübereinstimmung fehlschlägt, löst die Funktion bei Verwendung dieses Formulars einfach eine Ausnahme aus. Dies ist jedoch äußerst nützlich für Ihre Anwendungsfälle, insbesondere wenn Sie einen Vertrag über die Funktion stellen. Wie in der Dokumentation erwähnt:

...Es darf nur eine Übereinstimmungsklausel angegeben werden, da die Übereinstimmungsmuster mit der Formaldefinition übereinstimmen. Dies bedeutet, dass ein Fehler auftritt, wenn der Musterabgleich fehlschlägt, , aber es ist ideal, wenn eine Funktion bereits so kontrahiert ist, dass ein erfolgreicher Musterabgleich gewährleistet ist.

(Hervorhebung von mir.)

+0

Danke für das Paket! Werde es benutzen, habe es aber noch nicht getestet. Es ist mir immer noch nicht klar. Verträge sind Laufzeitprüfungen richtig? Nicht Kompilierzeit? Der Vorteil von Verträgen ist also eine bessere Laufzeit Ausnahme Fehlermeldung? Weil offensichtlich auch "no-more-moves-in-world?", Obwohl ausführlicher, eine Ausnahme auslöst, wenn Sie ihm zum Beispiel eine Zeichenfolge geben ... –

+0

@EmmanuelTouzery Richtig. Verträge lassen Sie Garantien verschlüsseln, die verschiedene Parteien erfüllen müssen, sonst wird ein Fehler ausgelöst. Wenn Sie Typed Racket verwenden, können Sie viele dieser Garantien auch zur Kompilierungszeit überprüfen, und dieses Paket * sollte * auch mit Type Racket funktionieren, mit ähnlichen Vorteilen. –

+0

Ich dachte nach. Ein Nachteil des Mustervergleichs besteht darin, dass es zusammenbricht, wenn Sie die Struktur ändern, z. B. ein neues Feld hinzufügen. In Lispes gibt es dafür keinen Kompilierungsfehler, und vielleicht ermutigt der Dev-Stil flüssigeres Arbeiten mit Datenstrukturen (mehr Änderungen im Verlauf der Entwicklung). Das klingt nach einem guten Grund, auch die Mustererkennung zu vermeiden. –

3

Ja, Sie könnten dieses Makro definitiv schreiben. Ich denke, es wäre ungefähr die Länge deines Beispiels, vielleicht kürzer.

Also, warum ist das nicht idiomatisch? Ich denke, dass die grundlegende Antwort das ist: Was sollte passieren, wenn es nicht zusammenpasst? Was, wenn Sie mehrere Muster bereitstellen möchten? Ich nehme an, dass Sie möglicherweise von einem Haskell-Hintergrund kommen, bei dem alle Muster-Übereinstimmungs-Definitionen zu einer einzigen Funktion verschmolzen sind. Ich denke, dass Scheme immer noch sehr vorsichtig ist, wenn es darum geht, die "ganze Funktionsdefinition ist in ein einzelnes Paar von Parens gehüllt" und weiter gefasst, "Bereiche sind in Klammern abgegrenzt." Es ist wahr, dass dies im Schläger ein wenig lockerer wird - jeder Lambda kann jetzt Definitionen direkt darin haben - aber ich denke, dass im Allgemeinen der "Geschmack" wäre, Ihre zweite Form zu verwenden, mit einer Übereinstimmung in einem Lambda mit einem benannten Argument.

Aber hey - das ist was Makros sind: Verwenden Sie das Formular, das Sie am besten lesen! Ich wäre glücklich, dieses Makro zusammen für Sie zu werfen, wenn Sie mögen.

+0

haha, kaputt über haskell! Ok ich verstehe. Alexis King hat ein fertiges Paket gegeben, also werde ich es benutzen. Bezogen auf was, wenn es nicht zusammenpasst - bereits 'no-more-moves-in-world?' Wird explodieren, wenn der Parameter nicht das ist, was erwartet wird, so? .. aber ich fragte diese Folgefrage auf Alexis 'Antwort . Vielen Dank! –

3

Der Vollständigkeit halber auch define/match ist, in #lang racket, das ist etwas ausführlicher als Alexis-Lösung und etwas weniger ausführlich als ein match im Körper.

#lang racket 
(struct dice-world (src board gt)) 
(struct game (board player moves)) 

(define/match (no-more-moves-in-world? w) 
    [((dice-world _ _ (game _ p _))) p]) 
+0

Sieht gut aus, danke! –

+1

Ah, ja, wahrscheinlich hätte ich das in meiner Antwort erwähnen sollen, haha ​​- das '*' am Ende von 'define/match *' ist es, zu vermeiden, mit 'define/match' zu kollidieren. –