Ricerca…
Sintassi
- Il
'
simbolo usato nell'esempio macroexpand è solo zucchero sintattico per l'operatorequote
. Potresti aver scritto(macroexpand (quote (infix 1 + 2)))
invece.
Osservazioni
Le macro sono solo funzioni che vengono eseguite in fase di compilazione, ovvero durante la fase di eval
in un ciclo di lettura-eval-print .
Le macro di Reader sono un'altra forma di macro che viene espansa in fase di lettura piuttosto che in fase di compilazione.
Best practice durante la definizione della macro.
- alpha-renaming, poiché la macro è espandibile potrebbe sorgere conflitto di nomi di binding. Il conflitto vincolante non è molto intuitivo da risolvere quando si utilizza la macro. Questo è il motivo per cui, ogni volta che una macro aggiunge un'associazione all'ambito, è obbligatorio utilizzare il simbolo
#
alla fine di ogni simbolo.
Macro Infix semplice
Clojure usa la notazione del prefisso, ovvero: L'operatore viene prima dei suoi operandi.
Ad esempio, una semplice somma di due numeri sarebbe:
(+ 1 2) ;; => 3
I macro ti consentono di manipolare la lingua Clojure in una certa misura. Ad esempio, è possibile implementare una macro che consente di scrivere codice in notazione infisso (ad es. 1 + 2
):
(defmacro infix [first-operand operator second-operand]
"Converts an infix expression into a prefix expression"
(list operator first-operand second-operand))
Analizziamo il codice sopra riportato:
-
defmacro
è un modulo speciale che usi per definire una macro. -
infix
è il nome della macro che stiamo definendo. -
[first-operand operator second-operand]
sono i parametri che questa macro si aspetta di ricevere quando viene chiamata. -
(list operator first-operand second-operand)
è il corpo della nostra macro. Crea semplicemente unalist
con i valori dei parametri forniti alla macroinfix
e restituisce quello.
defmacro
è una forma speciale perché si comporta in modo leggermente diverso rispetto ad altri costrutti Clojure: i suoi parametri non vengono immediatamente valutati (quando chiamiamo la macro). Questo è ciò che ci permette di scrivere qualcosa come:
(infix 1 + 2)
;; => 3
La macro infix
espanderà gli argomenti 1 + 2
in (+ 1 2)
, che è un modulo Clojure valido che può essere valutato.
Se vuoi vedere che cosa genera la macro infix
, puoi usare l'operatore macroexpand
:
(macroexpand '(infix 1 + 2))
;; => (+ 1 2)
macroexpand
, come implicito nel nome, espanderà la macro (in questo caso, utilizzerà la macro infix
per trasformare 1 + 2
in (+ 1 2)
) ma non consentirà di valutare il risultato dell'espansione macro Interprete di Clojure.
Sintassi quoting e unquotation
Esempio dalla libreria standard ( 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#))))
-
`
called syntax-quote è come(quote)
, ma ricorsivo: causa(let …)
,(if …)
, ecc per non valutare durante l'espansione della macro ma per produrre come è -
~
aka unquote annulla la sintassi-citazione per un modulo singolo all'interno di un modulo basato sulla sintassi. Quindi il valore dix
viene emesso quando si espande la macro (invece di emettere il simbolox
) -
~@
alias unquote-splicing è come unquote ma prende l'argomento list e lo espande, ogni elemento dell'elenco in forma separata -
#
aggiunge un ID univoco ai simboli per prevenire conflitti di nome. Aggiunge lo stesso id per lo stesso simbolo all'interno dell'espressione con sintassi, cosìand#
insidelet
eand#
insideif
otterrà lo stesso nome