Uma macro para fazer o que você deseja
Como um exercício de uma espécie:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Agora tente:
(setq-every "/foo/bar" f-loc1 f-loc2)
Como funciona
Como as pessoas têm curiosidade em saber como isso funciona (de acordo com os comentários), aqui está uma explicação. Para realmente aprender a escrever macros, escolha um bom livro Common Lisp (sim, Common Lisp, você poderá fazer o mesmo no Emacs Lisp, mas o Common Lisp é um pouco mais poderoso e possui melhores livros, IMHO).
Macros operam em código bruto. Macros não avaliam seus argumentos (ao contrário de funções). Portanto, temos aqui uma avaliação value
e uma coleção de vars
, que para nossa macro são apenas símbolos.
progn
agrupa várias setq
formas em uma. Essa coisa:
(mapcar (lambda (x) (list 'setq x value)) vars)
Apenas gera uma lista de setq
formulários, usando o exemplo do OP, será:
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Veja, o formulário está dentro do formulário de aspas anteriores e é prefixado com uma vírgula
,
. Dentro do formulário com aspas retroativas, tudo é cotado como de costume, mas ,
a avaliação mapcar
é ativada temporariamente, e toda a avaliação é avaliada no momento da macroexpansão.
Finalmente @
remove os parênteses externos da lista com setq
s, para obtermos:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
As macros podem transformar arbitrariamente seu código-fonte, não é ótimo?
Uma ressalva
Aqui está uma pequena ressalva: o primeiro argumento será avaliado várias vezes, porque essa macro se expande essencialmente para o seguinte:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Veja bem, se você tiver uma variável ou string aqui, tudo bem, mas se você escrever algo como isto:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Então sua função será chamada mais de uma vez. Isso pode ser indesejável. Aqui está como corrigi-lo com a ajuda de once-only
(disponível no
pacote 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 o problema se foi.