2012-08-14 14 views
23

Estoy aprendiendo acerca de las macros de Clojure, y los ejemplos de código a veces tendrán los constructos '~symbol o alternativamente ~'symbol. Sé que (quote y ' impiden que se evalúe un formulario, y que la comilla inversa agrega adicionalmente la calificación del espacio de nombres, y que ~ hace que se evalúe un formulario citado. Mi pregunta es: ¿por qué es útil detenerse y luego comenzar la evaluación? También asumo que ~'symbol y '~symbol son diferentes, pero ¿cómo?¿Cuál es el propósito de ~ 'o' ~ en Clojure?

Respuesta

30

~'symbol se utiliza para producir un sin calificar símbolo. Las macros de Clojure capturan el espacio de nombre de forma predeterminada, por lo que un símbolo en una macro normalmente se resolvería en (your-namespace/symbol). La expresión unquote-quote da como resultado directamente el nombre del símbolo simple, no calificado - (symbol) - mediante la evaluación de un símbolo entre comillas. De la alegría de Clojure:

(defmacro awhen [expr & body] 
    `(let [~'it ~expr] ; refer to the expression as "it" inside the body 
    (when ~'it 
     (do [email protected])))) 

(awhen [:a :b :c] (second it)) ; :b 

'~symbol es probable utiliza para insertar un nombre de la macro o algo similar. Aquí, symbol estará vinculado a un valor - let [symbol 'my-symbol]. Este valor se inserta en el código que produce la macro evaluando symbol.

(defmacro def-symbol-print [sym] 
    `(defn ~(symbol (str "print-" sym)) [] 
    (println '~sym))) ; print the symbol name passed to the macro 

(def-symbol-print foo) 
(print-foo) ; foo 
+0

:) Gracias, eso tiene sentido. – Alex

+0

todavía hay un punto que no me queda claro: '(unquote (quote user/foo))' da como resultado 'foo' en lugar de' user/foo', ¿cuándo y cómo ocurre que el espacio de nombres se elimina? ¿Cómo es consistente con el comportamiento "normal" de 'unquote' que evalúa la siguiente forma? – skuro

+1

El primer ejemplo no funciona. Debería ser '\' (let [~ 'it ~ expr] ... ' – Ming

4

~ es un lector de macros para la función unquote. dentro de una lista citado provoca un símbolo que va a evaluarse en lugar de utilizar como un símbolo literal

user> (def unquoted 4) 
user>`(this is an ~unquoted list) 
(user/this user/is user/an 4 clojure.core/list) 
user> 

todo excepto el símbolo no cotizados se utilizó simplemente como un símbolo donde no indicada se resolvió a su valor de 4. Este es más a menudo se usa para escribir macros. La réplica también imprime el espacio de nombre (usuario) delante de los nombres cuando está imprimiendo la lista resultante.

muchas macros, son básicamente solo plantillas diseñadas para hacer un montón de pequeñas variaciones en algo que no se puede hacer en una función. En este ejemplo artificial, una macro de plantilla define una función produciendo una llamada a def. sintaxis de la cotización con unquoting hace esto mucho más fácil de leer:

user> (defmacro def-map-reducer [name mapper reducer] 
     `(defn ~name [& args#] 
       (reduce ~reducer (map ~mapper args#)))) 

#'user/def-map-reducer 
user> (def-map-reducer add-incs inc +) 
#'user/add-incs 
user> (add-incs 1 2 3 4 5) 
20 

en comparación con:

user> (defmacro def-map-reducer [name mapper reducer] 
      (let [args-name (gensym)] 
       (list `defn name [`& args-name] 
        (list `reduce reducer (list `map mapper args-name))))) 

#'user/def-map-reducer 
user> (def-map-reducer add-decs dec +) 
#'user/add-decs 
user> (add-decs 1 2 3 4 5) 
10 
user> 

en el segundo ejemplo también no utilizar la función de auto-gensyms porque no soy de una sintaxis-cita

+0

Así que sé por qué querría usar ~ delante de un símbolo en una lista que había citado previamente, mi pregunta es específicamente por qué usaría ~ 'o' ~ uno al lado del otro. – Alex

+0

espero que este ejemplo muestre la motivación mejor, gracias por los comentarios :) –

Cuestiones relacionadas