Pregunta

Estoy leyendo el libro de Graham "On Lisp" y no puedo entender el siguiente ejemplo en la página 37:

If we define exclaim so that its return value
incorporates a quoted list,

(defun exclaim (expression)
  (append expression ’(oh my)))

>  (exclaim ’(lions and tigers and bears))
(LIONS AND TIGERS AND BEARS OH MY)
> (nconc * ’(goodness))
(LIONS AND TIGERS AND BEARS OH MY GOODNESS)

could alter the list within the function:

> (exclaim ’(fixnums and bignums and floats))
(FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS)

To make exclaim proof against such problems, it should be written:
(defun exclaim (expression)
  (append expression (list ’oh ’my)))

¿Alguien entiende lo que está pasando aquí?Esto está arruinando seriamente mi modelo mental de lo que hacen las citas.

¿Fue útil?

Solución

nconc es una operación destructiva que altera su primer argumento cambiando su cola. En este caso, significa que la lista constante '(oh my) recibe una nueva cola.

Para espero hacer esto más claro. Es un poco como esto:

; Hidden variable inside exclaim
oh_my = oh → my → nil

(exclaim '(lions and tigers and bears)) =
    lions → and → tigers → and → bears → oh_my

(nconc * '(goodness)) destructively appends goodness to the last result:
    lions → and → tigers → and → bears → oh → my → goodness → nil
so now, oh_my = oh → my → goodness → nil

Sustitución '(oh my) con correcciones (list 'oh 'my) esto porque ya no es una constante de ser compartida por todos y cada uno. Cada llamada a exclaim genera una nueva lista (propósito de la función list en la vida es crear nuevas listas).

Otros consejos

La observación de que su modelo mental de citar puede ser defectuoso es excelente, aunque puede aplicarse o no dependiendo de cuál sea ese modelo mental.

Primero, recuerde que existen varias etapas para la ejecución del programa.Un entorno Lisp debe primero leer el texto del programa en estructuras de datos (listas, símbolos y diversos datos literales, como cadenas y números).A continuación, puede o no compilar esas estructuras de datos en código de máquina o algún tipo de formato intermediario.Finalmente, el código resultante es evaluado (En el caso del código de máquina, por supuesto, esto puede significar simplemente saltar a la dirección apropiada).

Dejemos a un lado el tema de la compilación por ahora y centrémonos en las etapas de lectura y evaluación, suponiendo (para simplificar) que la entrada del evaluador es la lista de estructuras de datos leídas por el lector.

Considere una forma (QUOTE x) dónde X es alguna representación textual de un objeto.Esto puede ser un símbolo literal como en (QUOTE ABC), una lista literal como en (QUOTE (A B C)), una cadena literal como en (QUOTE "abc"), o cualquier otro tipo de literal.En la etapa de lectura, el lector leerá el formulario como una lista (llámelo formulario 1) cuyo primer elemento es el símbolo QUOTE y cuyo segundo elemento es el objeto X' cuya representación textual es X.Tenga en cuenta que estoy diciendo específicamente que el objeto X' está almacenado dentro de la lista que representa la expresión, es decir.en cierto sentido, se almacena como una parte del código mismo.

Ahora es el turno del evaluador.La aportación del evaluador es formulario 1, que es una lista.Entonces mira el primer elemento de formulario 1, y, habiendo determinado que es el símbolo QUOTE, devuelve como resultado de la evaluación el segundo elemento de la lista.Éste es el punto crucial.El evaluador devuelve el segundo elemento de la lista a evaluar, que es lo que el lector leyó en la primera etapa de ejecución (¡antes de la compilación!). Eso es todo lo que hace. No tiene nada de mágico, es muy simple y, significativamente, no se crean nuevos objetos ni se copian los existentes.

Por lo tanto, cada vez que modificas una “lista cotizada”, estás modificando el código en sí.El código automodificado es algo muy confuso y, en este caso, el comportamiento en realidad no está definido (porque ANSI Common Lisp permite que las implementaciones coloquen el código en la memoria de solo lectura).

Por supuesto, lo anterior es meramente un modelo mental.Las implementaciones son libres de implementar el modelo de varias maneras y, de hecho, no conozco ninguna implementación de Common Lisp que, como en mi explicación, no realice ninguna compilación.Aún así, esta es la idea básica.

En Common Lisp.

Recuerde:

'(1 2 3 4)

Por encima es un lista literal . datos constantes .

(list 1 2 3 4)

LISTA es una función que devuelve una llamada cuando nueva lista fresca con sus argumentos como elementos de la lista.

Evitar la modificación de las listas de literales. Los efectos no están estandarizados. Imagine un Lisp que recopila todos los datos constantes en una única área de escritura de memoria. Imagine un Lisp que se lleva a las listas y los comparte constantes en todas las funciones.

(defun a () '(1 2 3)

(defun b () '(1 2 3))

A Lisp compilador puede crear una lista que es compartida por ambas funciones.

Si modifica la lista devuelta por la función de un

  • no puede ser cambiado
  • podría ser cambiado
  • podría ser un error
  • También puede cambiar la lista devuelta por la función b

Las implementaciones tienen la libertad de hacer lo que les gusta. Esto deja espacio para optimizaciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top