A veces necesito establecer el mismo valor para múltiples variables.
En Python, podría hacer
f_loc1 = f_loc2 = "/foo/bar"
Pero en elisp, estoy escribiendo
(setq f_loc1 "/foo/bar" f_loc2 "/foo/bar")
Me pregunto si hay una manera de lograr esto usando "/foo/bar"
solo una vez.
source
ytarget
en la misma ruta al principio y podría cambiartarget
más tarde, ¿cómo configurarlos?Respuestas:
setq
devuelve el valor, por lo que puede simplemente:Si no quieres confiar en eso, usa:
Personalmente, evitaría lo último y en su lugar escribiría:
o incluso
Y el primer enfoque solo lo usaría en circunstancias bastante especiales donde realmente enfatiza la intención, o cuando la alternativa sería usar el segundo enfoque o de lo contrario
progn
.Puedes dejar de leer aquí si lo anterior te hace feliz. Pero creo que esta es una buena oportunidad para advertirle a usted y a otros que no abusen de las macros.
Finalmente, aunque es tentador escribir una macro como
setq-every
"porque esto es lisp y podemos", recomendaría encarecidamente que no lo haga. Ganas muy poco al hacerlo:Pero al mismo tiempo, hace que sea mucho más difícil para otros lectores leer el código y asegurarse de lo que sucede.
setq-every
podría implementarse de varias maneras y otros usuarios (incluido un futuro que usted) no pueden saber cuál elige el autor, simplemente mirando el código que lo usa. [Originalmente hice algunos ejemplos aquí, pero alguien los consideró sarcásticos y despotricaron].Puedes lidiar con esa sobrecarga mental cada vez que miras
setq-every
o puedes vivir con un solo personaje adicional. (Al menos en el caso de que tenga que establecer solo dos variables, pero no puedo recordar que alguna vez tuve que establecer más de dos variables al mismo valor a la vez. Si tiene que hacer eso, entonces probablemente haya algo más mal con tu código)Por otro lado, si realmente va a utilizar esta macro más de media docena de veces, entonces la indirección adicional podría valer la pena. Por ejemplo, uso macros como
--when-let
de ladash.el
biblioteca. Eso hace que sea más difícil para quienes lo encuentran por primera vez en mi código, pero vale la pena superar esa dificultad de comprensión porque se usa más que solo unas pocas veces y, al menos en mi opinión, hace que el código sea más legible .Se podría argumentar que lo mismo se aplica
setq-every
, pero creo que es muy poco probable que esta macro en particular se use más de unas pocas veces. Una buena regla general es que cuando la definición de la macro (incluida la cadena de documentos) agrega más código del que elimina el uso de la macro, es muy probable que la macro sea exagerada (lo contrario no es necesariamente cierto).fuente
setq
, puede hacer referencia a su nuevo valor, por lo que también podría usar esta monstruosidad:(setq a 10 b a c a d a e a)
que establece abcd ye en 10.Una macro para hacer lo que quieras
Como ejercicio de una especie:
Ahora pruébalo:
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
yvars
que, para nuestra macro, son solo símbolos.progn
agrupa variassetq
formas en una. Esta cosa:Simplemente genera una lista de
setq
formularios, usando el ejemplo de OP será: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 totalidadmapcar
se evalúa en el tiempo de macroexpansión.Finalmente
@
elimina el paréntesis externo de la lista consetq
s, por lo que obtenemos: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:
Verá, si tiene una variable o cadena aquí está bien, pero si escribe algo como esto:
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 ):Y el problema se ha ido.
fuente
value
en el momento de la macroexpansión.(macroexpand '(setq-every user-emacs-directory f-loc1 f-loc2))
->(progn (setq f-loc1 user-emacs-directory) (setq f-loc2 user-emacs-directory))
. Sivalue
se evaluaran en el tiempo de macroexpansión, se sustituiría con una cadena real. Puede colocar la llamada de función con efectos secundarios, en lugar devalue
, no se evaluará hasta que se ejecute el código expandido, pruébelo.value
como argumento de macro no se evalúa automáticamente. El problema real es quevalue
se evaluará varias veces, lo que puede ser indeseable,once-only
puede ayudar aquí.mmt-once-only
(que requiere una dep externa), podría usarmacroexp-let2
.set
, no para envolversetq
en una macro. O simplemente utilícelosetq
con múltiples argumentos, incluida la repetición de argumentos.Dado que puede usar y manipular símbolos en lisp, simplemente puede recorrer una lista de símbolos y usarlos
set
.fuente