2012-10-01 13 views
14

In Clojure müssen Sie gensym verwenden, um Symbole für den internen Gebrauch in Ihren Makros zu erstellen, um sie hygienisch zu halten. Manchmal müssen Sie jedoch das gleiche Symbol in verschachtelten Syntax-Anführungszeichen verwenden. Zum Beispiel, wenn ich einen Wert auf ein Symbol mit let und drucken Sie es dreimal in einer entrollten Schleife binden möchten, würde ichKoordinieren von Auto-Gensym in verschachtelten Syntax-Anführungszeichen in Clojure

`(let [x# 1] 
    [email protected](repeat 3 
      `(println x#))) 

tun Aber das würde produzieren

(clojure.core/let [x__2__auto__ 1] 
        (clojure.core/println x__1__auto__) 
        (clojure.core/println x__1__auto__) 
        (clojure.core/println x__1__auto__)) 

x# a erzeugt anderes Symbol in der let Form als in der println Formen darin verschachtelt - weil sie aus verschiedenen Syntax-Anführungszeichen erstellt wurden.

es zu lösen, kann ich das Symbol vorher erzeugen und an die Syntax-Zitate injizieren:

(let [x (gensym)] 
    `(let [~x 1] 
    [email protected](repeat 3 
       `(println ~x))) 
) 

Dies wird das richtige Ergebnis, mit dem gleichen Symbol erzeugen überall gebraucht:

(clojure.core/let [G__7 1] 
        (clojure.core/println G__7) 
        (clojure.core/println G__7) 
        (clojure.core/println G__7)) 

Jetzt, während es das richtige Ergebnis produziert, sieht der Code selbst hässlich und ausführlich aus. Ich mag es nicht, ein Symbol "deklarieren" zu müssen, und die Injektionssyntax lässt es so aussehen, als käme es von außerhalb des Makros oder irgendwo dazwischen berechnet. Ich möchte in der Lage sein, die Auto-Gensym Syntax zu verwenden, die klarstellt, dass das Makro-interne Symbole sind.

Also, gibt es eine Möglichkeit, Auto-Gensym mit verschachtelten Syntax-Anführungszeichen zu verwenden und sie das gleiche Symbol zu erzeugen?

Antwort

11

Auto-gensym'd-Symbole sind nur innerhalb des Syntax-Anführungszeichens gültig, das sie definiert, und sie funktionieren nicht in nicht-angekreuztem Code, da dies nicht Teil des Syntax-Zitats ist.

Hier ist das Symbol x# durch seine gensym ersetzt wird, weil es im Rahmen der Syntax Zitat ist:

core> `(let [x# 1] x#) 
(clojure.core/let [x__1942__auto__ 1] x__1942__auto__) 

Und wenn Sie es unquote es nicht länger wird übersetzt in es ist Syntax Zitat:

core> `(let [x# 1] [email protected]#) 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x# in this context, compiling:(NO_SOURCE_PATH:1) 

Auto-Gensyms sind eine sehr bequeme Abkürzung innerhalb des Syntax-Anführungsstrichs, überall wo Sie anscheinend gensym direkt verwenden müssen, wie es bei Ihrem späteren Beispiel der Fall ist.

Es gibt andere Möglichkeiten, dieses Makro so zu strukturieren, dass autogensyms funktionieren wird, obwohl das Generieren von Gensymed-Symbolen in einem Let an der Spitze eines Makros in Clojure und anderen Lisps ebenfalls sehr normal ist.

+0

Danke. Ich kann nicht normal unter Angabe der Druck Ausdruck zu arbeiten, aber ich nehme an, es sowieso für komplexere Makros lästig werden werde ... –

+0

Wenn Sie etwas tun, ich empfehlen \ 'println verwenden, nicht‚println - Ersteres unterliegt keiner Namensaufzeichnung, wenn der Makrobenutzer einen ungewöhnlichen Namespace oder lexikalischen Kontext hat. – amalloy

+0

guter Punkt! Ich werde bearbeiten, um das zu beheben –

8

Ihre Methode (Aufruf gensym) ist die richtige.

In einigen Fällen können Sie jedoch mit einer cleveren Verwendung von , -> oder ->> auskommen. Siehe:

`(let [x# 1] 
    (doto x# 
    [email protected](repeat 3 `println))) 
+0

Ich dachte tatsächlich über 'doto', aber konnte den Befehl nicht finden - ich suchte für etwas in der Art von "Dowith", weil ich das von anderen Sprachen gewohnt bin ... –

Verwandte Themen