Une macro pour faire ce que vous voulez
Comme un exercice en quelque sorte:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Essayez-le maintenant:
(setq-every "/foo/bar" f-loc1 f-loc2)
Comment ça marche
Puisque les gens sont curieux de savoir comment cela fonctionne (selon les commentaires), voici une explication. Pour vraiment apprendre à écrire des macros, choisissez un bon livre Common Lisp (oui, Common Lisp, vous pourrez faire la même chose dans Emacs Lisp, mais Common Lisp est un peu plus puissant et a de meilleurs livres, à mon humble avis).
Les macros fonctionnent sur du code brut. Les macros n'évaluent pas leurs arguments (contrairement aux fonctions). Nous avons donc ici non évalué value
et collection de vars
, qui pour notre macro ne sont que des symboles.
progn
regroupe plusieurs setq
formulaires en un seul. Cette chose:
(mapcar (lambda (x) (list 'setq x value)) vars)
Génère simplement une liste de setq
formulaires, en utilisant l'exemple d'OP, ce sera:
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Vous voyez, le formulaire est à l' intérieur du formulaire de guillemets et est préfixé par une virgule
,
. À l'intérieur de la forme entre guillemets, tout est cité comme d'habitude, mais l' ,
évaluation «active» temporairement, donc tout mapcar
est évalué au moment de la macroexpansion.
@
Supprime enfin les parenthèses externes de la liste avec setq
s, nous obtenons donc:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Les macros peuvent transformer arbitrairement votre code source, n'est-ce pas génial?
Une mise en garde
Voici une petite mise en garde, le premier argument sera évalué plusieurs fois, car cette macro se développe essentiellement comme suit:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Vous voyez, si vous avez une variable ou une chaîne ici, c'est OK, mais si vous écrivez quelque chose comme ceci:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Ensuite, votre fonction sera appelée plusieurs fois. Cela peut être indésirable. Voici comment le corriger à l'aide de once-only
(disponible dans le
package 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))))
Et le problème a disparu.