Una macro per fare quello che vuoi
Come esercizio di una specie:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Ora provalo:
(setq-every "/foo/bar" f-loc1 f-loc2)
Come funziona
Dato che le persone sono curiose di sapere come funziona (secondo i commenti), ecco una spiegazione. Per imparare davvero a scrivere macro scegli un buon libro Common Lisp (sì, Common Lisp, sarai in grado di fare le stesse cose in Emacs Lisp, ma Common Lisp è un po 'più potente e ha libri migliori, IMHO).
Le macro operano su codice non elaborato. Le macro non valutano i loro argomenti (a differenza delle funzioni). Quindi abbiamo qui non valutato value
e la raccolta di vars
, che per la nostra macro sono solo simboli.
progn
raggruppa diverse setq
forme in una. Questa cosa:
(mapcar (lambda (x) (list 'setq x value)) vars)
Genera solo un elenco di setq
moduli, usando l'esempio di OP sarà:
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Vedete, il modulo è all'interno del modulo backquote ed è preceduto da una virgola
,
. All'interno del modulo retroquistato, tutto viene quotato come al solito, ma la ,
valutazione "attiva" temporaneamente, quindi l'intero mapcar
viene valutato al momento dell'espansione macro.
@
Rimuove infine la parentesi esterna dall'elenco con setq
s, quindi otteniamo:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Le macro possono trasformare arbitrariamente il tuo codice sorgente, non è fantastico?
Un avvertimento
Ecco un piccolo avvertimento, il primo argomento verrà valutato più volte, poiché questa macro si espande essenzialmente a quanto segue:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Vedi, se hai una variabile o una stringa qui va bene, ma se scrivi qualcosa del genere:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Quindi la tua funzione verrà chiamata più di una volta. Questo potrebbe essere indesiderabile. Ecco come risolverlo con l'aiuto di once-only
(disponibile nel
pacchetto MMT ):
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE.
VALUE is only evaluated once."
(mmt-once-only (value)
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars))))
E il problema è sparito.