2016-08-09 15 views
0

kann ich viele Variablen zusammen wie folgt definieren:Neudefinition eine Liste von Variablen in Racket

(match-define (list a b c) (list 1 2 3)) 
a 
b 
c 

Ausgang:

1 
2 
3 
> 

Aber wie kann ich diese Variablen wieder später im Programm neu zu definieren?

Im Wesentlichen bin ich auf der Suche nach einer "Match-Redefine" -Funktion oder Makro.

Nach nicht funktioniert:

(set! (list a b c) (list 10 20 30)) 
set!: not an identifier in: (list a b c) 

ich auch versucht Kartenfunktion:

> (map set! (list a b c) (list 5 6 7)) 
. set!: bad syntax in: set! 
> 

Muss ich eine Funktion für sie schreiben oder gibt es eine einfache integrierte Methode?

Edit: Ich habe versucht, folgende Match-umdefinieren Makro, auf https://docs.racket-lang.org/guide/pattern-macros.html auf den Linien von Swap-Makro geschrieben:

(match-define (list a b c) (list 1 2 3)) 

(println "------- sl --------") 
(define sl (list a b c)) 
(println sl) 

(println "------- vl --------") 
(define vl (list 5 6 7)) 
(println vl) 

(define-syntax-rule (match-redefine slist vlist) 
    (for ((i slist) (j vlist)) 
    (set! i j) 
) 
) 

(println "----- expecting sl to become 5 6 7 ----------") 
(match-redefine sl vl) 
(println sl) 

Aber es funktioniert nicht. Die Ausgabe lautet:

"------- sl --------" 
'(1 2 3) 
"------- vl --------" 
'(5 6 7) 
"----- expecting sl to become 5 6 7 ----------" 
'(1 2 3) 

Edit: Ich fand, dass Spiel-let erlaubt Neuzuteilung mit Listen:

(define a 1) 
(define b 2) 
(define c 3) 

(match-let (( (list a b c) (list 100 200 300) )) 
    (println a) 
    (println b) 
    (println c) 
) 

Ausgang:

100 
200 
300 

Aber es ist kein 'definieren' oder " einstellen!' zur Verwendung über die gesamte verbleibende Quelldatei.

Antwort

3

Die Frage ist "Neudefinieren einer Liste von Variablen in Racket". Die Antwort ist, dass Sie nicht können!

Sie können eine Liste von Werten haben, aber keine Liste von Variablen. Der Ausdruck (list a b c) wertet auf eine Liste von drei Elementen:

> (define xs (list 1 2 3)) 
> xs 
(list 1 2 3) 

Jetzt Variable die xs ist, bezieht sich auf einen Wert (eine Liste:

> (define a 1) 
> (define b 2) 
> (define c 3) 
> (list a b c) 
(list 1 2 3) 

In Racket Sie einen Namen auf einen Wert geben kann drei Nummern).

können Sie ändern, was eine Variable set! zu verwenden bezieht:

> (set! xs (list 5 6 7)) 
(list 5 6 7) 

Wenn Sie möchten, die gleichzeitig drei Variablen ändern, können Sie set-values! verwenden.

> (set!-values (a b c) (values 8 9 10)) 
> a 
8 

Die Namen a, b und c sind Kennungen - Namen, die in Ihrem Programm auftreten. Dies bedeutet, dass Sie nicht in eine Liste einfügen können.

Durch Symbole kann man verwirrt:

> '(a b c) 
'(a b c) 

Hier werden die a,b,c Namen sind keine Variablen oder Bezeichner. Sie sind Symbole.

ohne Charakter um sich herum
> '("a" "b" "c") 
'("a" "b" "c") 

Symbole auf der anderen Seite gedruckt werden:

Eine Liste von Strings wird wie folgt gedruckt.

Wenn Sie ein Symbol haben a und wollen die Variable setzen, dessen Name a können Sie eval verwenden - aber es ist sehr selten, dass eval mit eine gute Idee ist. Ich werde es dir überlassen, den Ausdruck "eval is evil racket" zu googeln.

EDIT: Hinzugefügt fehlt nicht.

+0

Können wir das nicht mit einem Makro tun? Wie funktioniert Tausch auf dieser Seite https://docs.racket-lang.org/guide/pattern-macros.html? – rnso

+0

Vielleicht eine neue Frage, in der Sie das größere Bild erklären? – soegaard

+0

Makros wie 'swap' können funktionieren, weil Makros nicht mit Werten umgehen, sondern mit Syntax umgehen. Formen wie 'set!' Behandeln auch keine Werte und auch keine Makros wie 'match-define'. Das '(list a b c)' in einem 'match-define' Formular ist kein Wert. Um 'match-define' zu ​​definieren, ist es ein Stück Syntax, das zufällig aussieht wie ein' list' Funktionsaufruf. –

1

Sie können set!-values verwenden.

(match-define (list a b c) (list 1 2 3)) 
(set!-values (a b c) (values 10 20 30)) 
+0

Ich habe 2 Listen: (Liste a b c) und (Liste 10 20 30). Wie konvertiere ich sie in (a b c) und (Werte 10 20 30)? – rnso

3

@soegaard ist absolut richtig. Listen sind Werte und enthalten andere Werte als Variablen.

Allerdings, wenn ich Ihre Frage richtig bin zu lesen, ist es möglich, dass Sie nur eine nette Syntax für Pattern-Matching wollen einige Variablen mutieren je nachdem, wo sie im Muster erscheinen, so etwas wie:

> (define a 1) 
> (define b 2) 
> (define c 3) 
> (match-set! (list a b c) (list 10 20 30)) 
> a 
10 
> b 
20 
> c 
30 

Es ist ist möglich, dies zu tun, mit einem Makro, das eine local-expand auf einem konstruierten match-define Formular macht. Das hängt etwas von den internen Implementierungsdetails von match-define ab, also würde ich nicht empfehlen, es in echtem Code zu verwenden.

Dieses Makro wird einige zusätzliche Kompilierung-Manipulation tun Umwandlung define-values (die match-define in expandieren) in set!-values, so ist es eine gute Idee, eine Hilfsfunktion innerhalb eines begin-for-syntax zu schreiben, dass die Transformation zu tun.

#lang racket 
(require syntax/parse/define 
     (for-syntax syntax/parse ; for syntax-parse 
        syntax/stx)) ; for stx-map 

(begin-for-syntax 
    ;; defs->set!s : Syntax -> Syntax 
    ;; A helper function for match-set!, to transform define-values into set!-values 
    (define (defs->set!s defs) 
    (syntax-parse defs #:literals (begin define-values) 
     [(define-values [x ...] expr) 
     #'(set!-values [x ...] expr)] 
     [(begin defs ...) 
     #:with (set!s ...) (stx-map defs->set!s #'(defs ...)) 
     #'(begin set!s ...)]))) 

Dann muss das Makro eine match-define Form konstruieren, dann local-expand, dass in die define-values Formen zu erweitern verwenden, und verwenden Sie die defs->set!s Helferfunktion auf denen.

(define-syntax-parser match-set! 
    [(match-set! pat expr) 
    #:with defs 
    (local-expand #'(match-define pat expr) (syntax-local-context) #f) 
    (defs->set!s #'defs)]) 

Die Verwendung funktioniert genauso wie in den obigen Beispielen.

+0

Ja, es funktioniert gut. – rnso

+0

Ich habe dieses Match-Set gefunden! (auch match-let) funktioniert mit (list a b c) aber nicht, wenn solche Listen benannt wurden. Zum Beispiel funktioniert folgendes nicht: (definiere alist (list a b c)) (match-set! Alist (list 10 20 30)). Obwohl Alist einen Wert von (Liste 10 20 30) erhält, bleiben a und c unverändert. Kann dies durch Ihre elegante Codierung korrigiert werden? – rnso

+0

Ich glaube, ich habe es dir in einem anderen Kommentar gesagt, aber das '(list a b c)' in einem 'match'-Formular ist überhaupt kein Wert. Weder ist das 'x' in' (set! X 5) ', noch das' (list a b c) 'in einer' match-set! 'Form. Wenn Sie '(set! Alist (list 10 20 30))' 'geschrieben haben, würden Sie erwarten, dass sich' a', 'b' oder' c' ändern? –

2

einzustellen und mehr Variablen bei einer Verwendung define-values und set!-values zu aktualisieren:

(define-values (a b c) (values 1 2 3)) 
(set!-values (a b c) (values 2 3 4)) 

match soll nicht als eine allgemeine Art und Weise verwendet werden, um Variablen der Einstellung, sondern eine Art Struktur anzupassen und sie in Bindungen destrukturiert.

map wird nicht funktionieren, da es in der Laufzeit und nicht zur Kompilierzeit passiert. Sie können es zum Arbeiten hacken, wenn Sie Ihren eigenen Typ von Variablen einführen.

#lang racket 
(require srfi/26) 

(define-values (runtime-bounded? runtime-value? runtime-set! runtime-get runtime-set-values! runtime-get-values) 
    (let ((vars (make-hasheq))) 
    ;; a unique value to be our miss 
    (define fail (list "empty")) 

    ;; check if we have a symbol 
    (define (bounded? name) 
     (hash-has-key? vars name)) 

    ;; check if a value is not our miss 
    (define (value? val) 
     (not (eq? fail val))) 

    ;; single operations 
    (define (set! name val) 
     (hash-set! vars name val)) 
    (define (get name (default fail)) 
     (hash-ref vars name default)) 

    ;; list operations 
    (define (set-values! names values) 
     (for-each set! names values)) 
    (define (get-values names (default fail)) 
     (map (cut get <> default) names)) 

    ;; bind them to global symbols 
    (values bounded? value? set! get set-values! get-values))) 

Es funktioniert wie folgt:

(define lst-names '(a b c)) 
(define lst-values '(1 2 3)) 
(runtime-set-values! lst-names lst-values) 
(runtime-get-values '(a b c))    ; (1 2 3) 
(runtime-get 'a)       ; ==> 1 
(runtime-set! 'a 10) 
(runtime-get 'x 1337)      ; 1337 
(runtime-get-values '(a x) #f)    ; (10 #f) 

;; use map/for-each to set something 
(for-each (cut runtime-set! <> 10) '(x y z)) ; sets x y z to 10 

Dies ist flach, aber mit einigen Optimierungen könnte man sogar in der Lage sein, auch diese Mimik lexikalische Struktur zu machen. Dann wiederum könnte man stattdessen parameters betrachten.

Die Leistung wäre schlechter als die Verwendung tatsächlicher Variablen, aber in den meisten Fällen ist dies nicht der Fall.