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.

sourceytargeten la misma ruta al principio y podría cambiartargetmás tarde, ¿cómo configurarlos?Respuestas:
setqdevuelve 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-everypodrí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-everyo 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-letde ladash.elbiblioteca. 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
valueyvarsque, para nuestra macro, son solo símbolos.prognagrupa variassetqformas en una. Esta cosa:Simplemente genera una lista de
setqformularios, 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 totalidadmapcarse evalúa en el tiempo de macroexpansión.Finalmente
@elimina el paréntesis externo de la lista consetqs, 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
valueen 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)). Sivaluese 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.valuecomo argumento de macro no se evalúa automáticamente. El problema real es quevaluese evaluará varias veces, lo que puede ser indeseable,once-onlypuede ayudar aquí.mmt-once-only(que requiere una dep externa), podría usarmacroexp-let2.set, no para envolversetqen una macro. O simplemente utilícelosetqcon 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