2016-08-09 6 views
1

Ich benutze das auf dieser Seite erwähnte Makro (Macro for keyword and default values of function arguments in Racket), das erlaubt, {arg_name arg_value} für default und benannte Argumente (ohne die Notwendigkeit von #: key_name) zu verwenden. Ansonsten funktioniert es gut, aber es behindert die Deklaration von Funktionen mit variablen Argumenten (fnname. Vars). Der Fehler ist einfach "schlechte Syntax". Wie kann das korrigiert werden? Danke für deine Kommentare/Antworten.Schlüsselwort und Standardargumentmakro interferieren mit variablen Argumenten im Racket

Edit: Mein aktueller Code ist:

(require syntax/parse/define ; for define-simple-macro 
     (only-in racket [define old-define] [#%app old-#%app]) 
     (for-syntax syntax/stx)) ; for stx-map 

(begin-for-syntax 
    ;; identifier->keyword : Identifer -> (Syntaxof Keyword) 
    (define (identifier->keyword id) 
    (datum->syntax id (string->keyword (symbol->string (syntax-e id))) id id)) 
    ;; for use in define 
    (define-syntax-class arg-spec 
    [pattern name:id 
      ;; a sequence of one thing 
      #:with (norm ...) #'(name)] 
    [pattern {name:id default-val:expr}     ; rn: ch if {} needed here; since works well with [] here; 
      #:when (equal? #\{ (syntax-property this-syntax 'paren-shape)) 
      #:with name-kw (identifier->keyword #'name) 
      ;; a sequence of two things 
      #:with (norm ...) #'(name-kw {name default-val})])) 

(define-syntax-parser define   ; instead of define-simple-macro; 
    [(define x:id val:expr) 
    #'(old-define x val)] 
    [(define (fn arg:arg-spec ...) body ...+) 
    #'(old-define (fn arg.norm ... ...) body ...)]) 

(begin-for-syntax 
    ;; for use in #%app 
    (define-syntax-class arg 
    [pattern arg:expr 
      #:when (not (equal? #\{ (syntax-property this-syntax 'paren-shape))) 
      ;; a sequence of one thing 
      #:with (norm ...) #'(arg)] 
    [pattern {name:id arg:expr} 
      #:when (equal? #\{ (syntax-property this-syntax 'paren-shape)) 
      #:with name-kw (identifier->keyword #'name) 
      ;; a sequence of two things 
      #:with (norm ...) #'(name-kw arg)])) 

(require (for-syntax (only-in racket [#%app app]))) 

(define-simple-macro (#%app fn arg:arg ...) 
    #:fail-when (app equal? #\{ (app syntax-property this-syntax 'paren-shape)) 
    "function applications can't use `{`" 
    (old-#%app fn arg.norm ... ...)) 

Ich bin nicht sicher, welcher Teil zu ändern. Wenn ich den letzten Teil entferne (define-simple-macro), funktionieren die benannten/default-Argumente in {} nicht.

Weitere Edit: Ich habe den Code wie folgt geändert:

(define-syntax-parser define   ; instead of define-simple-macro; 
    [(define x:id val:expr) 
    #'(old-define x val)] 
    [(define (fn arg:arg-spec ...) body ...+) 
    #'(old-define (fn arg.norm ... ...) body ...)] 
    [(define (fn . vars) body ...+) 
    #'(old-define (fn . vars) body ...)]  ) 

und es funktioniert:

(define (testvars . vars) 
    (println (list? vars)) 
    (for ((item vars))(println item)) ) 

(testvars 1 2 3) 
#t 
1 
2 
3 

Aber warum muss ich noch brauchen "(define-simple-Makro .." -Teil ? auch, warum brauche ich 2 "(begin-for-Syntax .." Definitionen

Bearbeiten wieder: weitere Änderung:

(define-syntax-parser define   
    [(define x:id val:expr) 
    #'(old-define x val)] 
    [(define (fn arg:arg-spec ...) body ...+) 
    #'(old-define (fn arg.norm ... ...) body ...)] 
    [(define (fn arg:arg-spec ... . vars) body ...+)     
    #'(old-define (fn arg.norm ... ... . vars) body ...)] 
) 

Oben funktioniert schließlich sowohl mit benannten als auch variablen Argumenten, z. (Fnname {x 0} {y 1} 10 20 30), dank der Hilfe von @AlexKnauth in den Kommentaren unten.

+1

Das 'define' Makro in dieser Frage/Antwort unterstützt nicht das Deklarieren von" rest "Argumenten. Als ich es geschrieben habe, wollte ich die Implementierung nicht mit Funktionen überladen, die nicht wirklich relevant waren. –

+0

Obwohl es eigentlich nicht schwer für Sie sein sollte, es selbst zu erweitern. Anstelle von 'define-simple-macro' müssten Sie [' define-syntax-parser'] (http://docs.racket-lang.org/syntax/Defining_Simple_Macros.html#%28form._%28) verwenden % 28lib._syntax% 2Fparse% 2Fdefine..rkt% 29._define-Syntax-Parser% 29% 29), mit zwei Fällen, einer für, wenn es kein Restargument gibt, und einer, wo es gibt. –

+1

Die Definiere ist diejenige, die Sie ändern müssen, und das ist bereits mit 'define-syntax-parser' geschrieben. Ich hatte es vergessen, aber das macht es leichter. Sie müssen nur einen weiteren Fall zu dem bestehenden Makro 'define' hinzufügen. –

Antwort

1

Wie wir in den Kommentaren herausgefunden, alles, was Sie tun müssen, ist, einen dritten Fall des hinzufügen define Makro, ähnlich den zweiten Fall, aber mit einem . rst nach den arg:arg-spec ... im Muster und wieder nach den arg.norm ... ... in der Vorlage.

Der zweite Fall war

[(define (fn arg:arg-spec ...) body ...+) 
    #'(old-define (fn arg.norm ... ...) body ...)] 

Der neue Fall ist ähnlich, aber mit den . rst

hinzugefügt
[(define (fn arg:arg-spec ... . rst) body ...+)     
    #'(old-define (fn arg.norm ... ... . rst) body ...)] 

Im Kontext sieht es so.

+0

Könnten Sie eine gute Verbindung (en) zur Makrosyntax geben? – rnso

+0

Ich würde zuerst empfehlen, [Fear of Macros] (http://www.greghendershott.com/fear-of-macros/), dann die [syntax-parse Einführung] (http://docs.racket-lang.org/syntax/stxparse-intro.html) –

Verwandte Themen