2012-10-01 6 views
14

En Clojure, necesita usar gensym para crear símbolos para uso interno en sus macros para mantenerlos higiénicos. Sin embargo, a veces necesita usar el mismo símbolo en las comillas de sintaxis anidadas. Por ejemplo, si quiero enlazar un valor de un símbolo con let e imprimirlo tres veces en un bucle desenrollado, lo haríaCoordinar auto-gensym en sintaxis-citas anidadas en Clojure

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

Pero que produciría

(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# genera una símbolo diferente en el formulario let que en los formularios println anidados en él, porque se crearon a partir de diferentes citas de sintaxis.

para resolverlo, puedo generar el símbolo de antemano y lo inyecta a la sintaxis de las frases:

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

Esto producirá el resultado correcto, con el mismo símbolo en todas partes es necesario:

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

Ahora, si bien produce el resultado correcto, el código en sí parece feo y detallado. No me gusta tener que "declarar" un símbolo, y la sintaxis de inyección hace que parezca que proviene de fuera de la macro, o que se calcula en algún lugar dentro de ella. Quiero poder usar la sintaxis auto-gensym, lo que deja en claro que esos son símbolos macro internos.

Entonces, ¿hay alguna forma de usar auto-gensym con las comillas de sintaxis anidadas y hacer que produzcan el mismo símbolo?

Respuesta

11

Los símbolos autogenerados solo son válidos dentro de la sintaxis-cita que los define y no funcionan en código sin comillas porque no es parte de la cita de sintaxis.

Aquí el símbolo x# es reemplazado por Es gensym porque está dentro del alcance de la cita sintaxis:

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

Y si Unquote que ya no se traduce en que es la sintaxis cita:

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

Los gensimos automáticos son un atajo muy conveniente dentro de la sintaxis, en todos los sitios donde aparentemente necesita usar gensym directamente como en el caso de su ejemplo posterior.

hay otras formas de estructurar esta macro, por lo que los autogensyms funcionarán aunque declarar símbolos gensymed en un let en la parte superior de una macro es muy normal en Clojure y en otros ceceos también.

+0

Gracias. No me puedo poner normal, citando la expresión de impresión para que funcione, pero supongo que será engorroso para macros más complejos de todos modos ... –

+0

Si haces algo así, te recomiendo usar \ 'println, not 'println - el primero no está sujeto a la captura de nombre en caso de que el macro usuario tenga un espacio de nombre inusual o un contexto léxico. – amalloy

+0

¡buen punto! Voy a editar para arreglar ese –

8

Su método (llamar gensym) es el correcto.

Sin embargo, en algunos casos se puede pasar con un uso inteligente de doto, -> o ->>. Ver:

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

Realmente pensé en usar 'doto', pero no pude encontrar el comando - Estaba buscando para algo parecido a 'dowith', porque eso es a lo que estoy acostumbrado de otros lenguajes ... –