Una macro para hacer lo que quieras
Como ejercicio de una especie:
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
Ahora pruébalo:
(setq-every "/foo/bar" f-loc1 f-loc2)
Como funciona
Como la gente siente curiosidad por cómo funciona (según los comentarios), aquí hay una explicación. Para aprender realmente cómo escribir macros, elija un buen libro de Common Lisp (sí, Common Lisp, podrá hacer lo mismo en Emacs Lisp, pero Common Lisp es un poco más poderoso y tiene mejores libros, en mi humilde opinión).
Las macros funcionan con código sin formato. Las macros no evalúan sus argumentos (a diferencia de las funciones). Así que aquí tenemos una evaluación sin evaluar value
y vars
que, para nuestra macro, son solo símbolos.
progn
agrupa varias setq
formas en una. Esta cosa:
(mapcar (lambda (x) (list 'setq x value)) vars)
Simplemente genera una lista de setq
formularios, usando el ejemplo de OP será:
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
Verá, el formulario está dentro del formulario de comillas invertidas y tiene como prefijo una coma
,
. Dentro de la forma retrocomillada, todo se cita como de costumbre, pero la ,
evaluación "se enciende" temporalmente, por lo que la totalidad mapcar
se evalúa en el tiempo de macroexpansión.
Finalmente @
elimina el paréntesis externo de la lista con setq
s, por lo que obtenemos:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Las macros pueden transformar arbitrariamente su código fuente, ¿no es genial?
Una advertencia
Aquí hay una pequeña advertencia, el primer argumento se evaluará varias veces, porque esta macro se expande esencialmente a lo siguiente:
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
Verá, si tiene una variable o cadena aquí está bien, pero si escribe algo como esto:
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
Entonces su función se llamará más de una vez. Esto puede ser indeseable. Aquí se explica cómo solucionarlo con la ayuda de once-only
(disponible en el
paquete 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))))
Y el problema se ha ido.