Buscar..
Sintaxis
- El símbolo
'
usado en el ejemplo de macroexpand es solo azúcar sintáctica para el operador dequote
. Podría haber escrito(macroexpand (quote (infix 1 + 2)))
lugar.
Observaciones
Las macros son solo funciones que se ejecutan en tiempo de compilación, es decir, durante el paso de eval
en un ciclo de lectura-eval-print .
Las macros del lector son otra forma de macro que se expande en el momento de la lectura, en lugar del tiempo de compilación.
Mejores prácticas a la hora de definir macro.
- alfa-cambio de nombre, ya que la macro es expandir enlace podría surgir un conflicto. El conflicto de enlace no es muy intuitivo de resolver cuando se utiliza la macro. Esta es la razón por la cual, cuando una macro agrega un enlace al alcance, es obligatorio usar el
#
al final de cada símbolo.
Macro Infix simple
Clojure usa la notación de prefijo, es decir: el operador aparece antes que sus operandos.
Por ejemplo, una suma simple de dos números sería:
(+ 1 2) ;; => 3
Las macros te permiten manipular el lenguaje de Clojure hasta cierto punto. Por ejemplo, podría implementar una macro que le permita escribir código en notación de infijo (por ejemplo, 1 + 2
):
(defmacro infix [first-operand operator second-operand]
"Converts an infix expression into a prefix expression"
(list operator first-operand second-operand))
Vamos a desglosar lo que hace el código anterior:
-
defmacro
es una forma especial que se utiliza para definir una macro. -
infix
es el nombre de la macro que estamos definiendo. -
[first-operand operator second-operand]
son los parámetros que esta macro espera recibir cuando se llama. -
(list operator first-operand second-operand)
es el cuerpo de nuestra macro. Simplemente crea unalist
con los valores de los parámetros proporcionados a la macroinfix
y los devuelve.
defmacro
es una forma especial porque se comporta de manera un poco diferente en comparación con otras construcciones de Clojure: sus parámetros no se evalúan de inmediato (cuando llamamos a la macro). Esto es lo que nos permite escribir algo como:
(infix 1 + 2)
;; => 3
La macro infix
expandirá los argumentos 1 + 2
a (+ 1 2)
, que es una forma de Clojure válida que puede ser evaluada.
Si desea ver lo que genera la macro infix
, puede usar el operador de macroexpand
:
(macroexpand '(infix 1 + 2))
;; => (+ 1 2)
macroexpand
, como lo macroexpand
su nombre, expandirá la macro (en este caso, usará la macro infix
para transformar 1 + 2
en (+ 1 2)
) pero no permitirá que el resultado de la expansión de macro sea evaluado por Intérprete de clojure
Sintaxis citando y sin citar
Ejemplo de la biblioteca estándar ( core.clj: 807 ):
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
{:added "1.0"}
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
-
`
llamado syntax-quote es como(quote)
, pero recursivo: hace(let …)
,(if …)
, etc. no se evalúa durante la expansión de macros sino que se genera como está -
~
aka unquote cancela syntax-quote para una sola forma dentro de la forma sintaxis entre comillas. Entonces, el valor dex
se genera al expandir la macro (en lugar de mostrar el símbolox
) -
~@
aka unquote-splicing es como unquote pero toma el argumento de la lista y lo expande, cada elemento de la lista se forma de forma separada -
#
agrega una identificación única a los símbolos para evitar conflictos de nombre. Agrega la misma ID para el mismo símbolo dentro de la expresión entre comillas de sintaxis, por lo queand#
dentro delet
yand#
insideif
obtendremos el mismo nombre