Le macro restituiscono un elenco che viene quindi valutato nello spazio dei nomi da cui viene chiamato, non nello spazio dei nomi in cui è definito. Ciò è diverso dalle funzioni che valutano nello spazio dei nomi in cui sono definite. Questo è perché le macro restituiscono il codice da eseguire, invece di eseguirlo.
se vado ad un altro spazio dei nomi, per esempio hello.core
ed espandere una chiamata a next-date ottengo:
hello.core> (macroexpand-1 '(next-date weeks 2))
(weeks 2)
poi, dopo l'espansione, settimane è stato risolto da hello.core, in cui è ovviamente non definito. per risolvere questo problema abbiamo bisogno che il simbolo restituito porti con sé le informazioni sul nome-spazio.
per fortuna è possibile risolvere esplicitamente un simbolo in un namespace con ns-resolve
. Ci vuole uno spazio dei nomi e un simbolo e cerca di trovare nel ritorno nullo spazio dei nomi, se non è trovato
(ns-resolve 'clj-time.core (symbol "weeks"))
#'clj-time.core/weeks
prossimo la macro sarà tenuto un simbolo e un numero così possiamo fare a meno con la chiamata esplicita a symbol
(ns-resolve 'clj-time.core 'weeks)
#'clj-time.core/weeks
così ora solo bisogno di una funzione che consente di risolvere la funzione e quindi crea un elenco della funzione risolto seguito dal numero,
(defmacro next-date [interval freq]
(list (ns-resolve 'clj-time.core interval) freq))
Nella sopra macro non fa altro che effettuare una chiamata di funzione che è chiamata immediatamente, in modo da non avrete nemmeno bisogno di una macro per questo:
(defn next-date [interval freq]
((ns-resolve 'clj-time.core interval) freq))
(next-date 'weeks 2)
#<Weeks P2W>
la versione non-macro richiede di citare l'intervallo perché non è necessario valutarlo prima di poterlo consultare. Quello che la macro ti compra davvero non deve includere la citazione, al costo di richiedere a tutti i chiamanti di richiedere clj-
ovviamente potresti anche solo richiedere clj-time ovunque, ma questo non è proprio il punto .
Perché è necessario scrivere una macro. Non potrebbe essere fatto da una funzione regolare? Ricorda: non dovresti mai scrivere una macro quando una funzione lo farà. – viebel