2012-10-09 10 views
7

Für die Praxis habe ichÄrger mit clojure Zitat-paren `(...) Makro

(defmacro quote-paren 
    "body -> `(body)" 
    [& body] 
    `([email protected])) 

definiert, die die erwartete Transformation hat (quote-paren body) =>` `(Körper)`. Es scheint, ein paar grundlegende Tests zu erfüllen:

user=> (macroexpand-1 `(quote-paren 3 4 5)) 
(3 4 5) 
user=> (macroexpand-1 `(quote-paren println "hi")) 
(clojure.core/println "hi") 
user=> (macroexpand-1 `(quote-paren (println "hi"))) 
((clojure.core/println "hi")) 

Allerdings habe ich es getestet mit dieser do-while-Makro (modifiziert nach here):

(defmacro do-while 
    [test & body] 
    (quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 

(def y 4) 
(do-while (> y 0) 
    (def y (dec y))) 

Aber das Ergebnis ist

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote-splicing clojure.lang.Var$Unbound.throwArity (Var.java:43) 

Ich verstehe das nicht, denn von dem, was ich sehen kann, funktioniert das `quote-paren'-Makro gut (mit ~ @ Körper eingesteckt):

user=> (macroexpand-1 
     `(quote-paren loop [] 
      (def y (dec y)) 
      (when ~test 
       (recur)))) 

(clojure.core/loop [] (def user/y (clojure.core/dec user/y)) (clojure.core/when #<core$test [email protected]> (recur))) 

Aber versucht zu macroexpand do-while verursacht eine "unbound fn". Gibt es etwas Feines, das ich vermisse?

Antwort

3

fehlt die Syntax-Zitat vor quote-paren

user> (defmacro do-while 
    [test & body] 
    `(quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 
#'user/do-while 

, die dann richtig erweitert:

user> (macroexpand '(do-while (> y 0) 
         (def y (dec y)))) 
(loop* [] (def y (dec y)) (clojure.core/when (> y 0) (recur))) 

und scheint zu funktionieren:

user> (def y 4) 
#'user/y 
user> (do-while (> y 0) 
    (def y (dec y))) 
nil 
user> 
+1

und nur als Neben Kommentar: mit (def y ...) for loop control kann unbeabsichtigte Folgen haben, die nichts mit dieser Frage zu tun haben ;-) –

+0

Hmm, du hast Recht, aber das ist der Zweck meiner Übung. Gibt es überhaupt einen Zitat-Paren, der "(quote-paren stuff)" durch "(stuff)" ersetzt? Kurz gesagt, es ist unnötig, in der Makrodefinition zu schreiben. – spacingissue

+0

Ich habe versucht, '(quote-paren stuff)' durch '(quote (stuff))' zu ersetzen, aber es scheint aufgehört zu haben, die Variablen zu erkennen; das heißt '(defmacro do-while [Test & body] (Zitat (loop [] ~ @ Körper (bei ~ Test (wiederholen)))))' und Ergebnisse in 'CompilerException java.lang läuft. RuntimeException: Das Symbol symbol: body konnte in diesem Kontext nicht aufgelöst werden. Kompilieren: (NO_SOURCE_PATH: 58) 'Wenn dies in einer anderen Frage am besten angesprochen wird, würde ich es verstehen. – spacingissue