Me estoy enseñando un poco más de elisp y he encontrado el siguiente problema:
Si quiero restablecer una variable de lista, no se actualizará después de la primera evaluación. Aquí hay un código de ejemplo:
(defun initilize ()
(setq example '(3)))
(defun modify ()
(initilize)
(message "%S" example)
(setcar example 2))
; M-x eval-buffer RET
(modify) ; message --> (3)
(modify) ; message --> (2)
(modify) ; message --> (2)
Estoy interesado en dos cosas. La primera es aprender más sobre lo que está sucediendo "bajo el capó", entonces, ¿por qué funciona la primera vez y falla en llamadas posteriores?
La segunda pregunta, más práctica, es cómo reiniciar la lista correctamente o ¿hay otra forma común de hacer algo así?
Una solución alternativa que encontré es usar una lista citada y evaluar el contenido de esta manera:
(setq example `(,3))
list
quote
mutability
clemera
fuente
fuente

'(some list)a estareqa'(some list)- nunca .Hay general hay garantía de que en Lisp código que visiblemente cita una lista de declaraciones de nueva estructura de la lista cada vez. En algunas implementaciones de Lisp podría, o podría ser, algunas veces. En otros, nunca lo hace. Su código no debería depender de ningún comportamiento de la implementación. Si quieres nueva estructura de la lista, el usolistoconso equivalente.examplenunca se ha declarado como una variable, por lo quesetqdebe actuar como si declarara una nueva variable, pero más tarde, cuando llameinitializenuevamente, se creará una nueva variable, mientrasmodifyrecuerda la anterior ... en cualquier caso, este no es un comportamiento esperado, sin embargo, el uso desetqalgo que no se ha introducido anteriormente como una variable también podría estar indefinido.'(3)se trata como un valor literal, así que una vez(setcar '(3) 2), cada vez que haces(defvar foo '(3))o(let ((foo '(3)))etc. Es probable que obtener un valor defooigual a'(2). Digo "probable" porque este comportamiento no está garantizado, es un tipo de optimización que el intérprete hace cuando se siente, algo conocido como eliminación de subexpresiones constantes (un caso particular de). Entonces, lo que escribió abo-abo no es exactamente la razón. Es más como modificar un literal de cadena en C (que generalmente genera una advertencia).Respuestas:
Quizás esto aclare algo de la confusión:
Su función
initilizeno inicializa la variableexample. Lo establece en una celda de contra en particular: la misma celda de contras cada vez que se llama. La primera vez queinitilizese llama, sesetqasignaexamplea una nueva celda de contras, que es el resultado de la evaluación'(3). Llamadas posteriores parainitilizesimplemente reasignarexamplea la misma celda de contras.Dado que
initilizesolo reasigna la misma celda de contrasexample,modifysolo establece el auto de esa misma celda de contras2cada vez que se llama.Para inicializar una lista, use
listocons(o un sexp entre comillas equivalente, como`(,(+ 2 1))o`(,3)). Por ejemplo, use(list 3).La clave para comprender esto es saber que una celda contratada entre comillas se evalúa solo una vez, y luego se devuelve la misma celda contra. Esta no es necesariamente la forma en que se comportan todos los Lisps, pero es cómo se comporta Emacs Lisp.
De manera más general, el comportamiento de evaluar un objeto mutable entre comillas depende de la implementación, si no del lenguaje. En Common Lisp, por ejemplo, estoy bastante seguro de que no hay nada en la definición (especificación) del lenguaje que defina el comportamiento a este respecto; se deja a la implementación.
Resumen: No espere que '(alguna lista) sea igual a' (alguna lista), nunca. Por lo general, no hay garantía en Lisp de que el código que cita visiblemente una lista devuelva una nueva estructura de lista cada vez. En algunas implementaciones de Lisp podría, o podría ser, algunas veces. En otros, nunca lo hace. Su código no debería depender de ningún comportamiento de la implementación. Si quieres nueva estructura de la lista, el uso
listoconso equivalente.fuente
Puede usar
(setq example (list 3))para evitar este error.Lo que pasa es
initcesionarios un objeto que inicialmente contiene(3)aexample. Establece el valor del objeto solo una vez. Posteriormente, modifica este valor.Aquí está su ejemplo en C ++, si lo entiende mejor:
fuente
initilizefunción y llamomodifynuevamente, se mostrará(3)nuevamente solo porque reevalúe la función.(3)es un objeto temporal del que forma parteinit.initEl cuerpo se ajustaexamplea la dirección de ese objeto temporal, no toca su valor.