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é valueet collection de vars, qui pour notre macro ne sont que des symboles.
prognregroupe plusieurs setqformulaires en un seul. Cette chose:
(mapcar (lambda (x) (list 'setq x value)) vars)
Génère simplement une liste de setqformulaires, 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 mapcarest évalué au moment de la macroexpansion.
@Supprime enfin les parenthèses externes de la liste avec setqs, 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.