Aquí hay un diagrama que representa el símbolo a
y su valor después de (setq a '(1 2))
. Los recuadros son estructuras de datos elementales (símbolos y conses) y las flechas son punteros (donde una parte de los datos hace referencia a otra). (Estoy simplificando un poco.)
symbol cons cons
+-------+----------+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: |
| a | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+------+
| ↑ | ↑
+-------------+ +-------+
La expresión '(1 2)
construye los dos conses a la derecha, que conforman una lista de dos elementos. La expresión (setq a '(1 2))
crea el símbolo a
si no existe, luego hace que su "ranura variable" (la parte que contiene el valor del símbolo) apunte a la lista recién creada. setq
es una macro incorporada, y (setq a '(1 2))
es la abreviatura de (set 'a '(1 2))
. El primer argumento de set
es el símbolo para modificar y el segundo argumento es el valor para establecer la ranura variable del símbolo.
(add-to-list 'a 3)
es equivalente a (set 'a (cons 3 a))
aquí, porque 3 no está en la lista. Esta expresión hace cuatro cosas:
- Crea una nueva celda de cons.
- Establezca el nuevo campo de coche de la celda de cons en
3
.
- Establezca el nuevo campo cdr de la celda cons para el valor anterior (y aún actual) de
a
(es decir, copie el contenido de la ranura variable de a
).
- Establezca la ranura variable de
a
en la nueva celda de cons.
Después de esa llamada, las estructuras de datos involucrados mirada como esto:
symbol cons cons cons
+-------+----------+ +------+--|---+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: | |car: |cdr: |
| a | | | | 3 | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+--|---+ +------+------+
| ↑ | ↑ | ↑
+-------------+ +-------+ +-------+
La llamada a setcar
no crea ninguna nueva estructura de datos, y no actúa en el símbolo a
sino en su valor, que es la célula contras cuya car
contiene actualmente 3. Después (setcar a 4)
, las estructuras de datos el siguiente aspecto:
symbol cons cons cons
+-------+----------+ +------+--|---+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: | |car: |cdr: |
| a | | | | 4 | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+--|---+ +------+------+
| ↑ | ↑ | ↑
+-------------+ +-------+ +-------+
push
es una macro; aquí, (push 5 a)
es equivalente a (set 'a (cons 5 a))
.
setq
y push
son macros (setq
es una “forma especial”, que por lo que nos preocupa aquí significa una macro cuya definición está incorporado en el intérprete y no previsto en Lisp). Las macros reciben sus argumentos sin evaluar y pueden elegir expandirlos o no. set
, setcar
y add-to-list
son funciones que reciben sus argumentos evaluados. La evaluación de un símbolo devuelve los contenidos de su ranura variable, p. después del (setq a '(1 2))
inicial, el valor del símbolo a
es la celda de cons cuyo automóvil contiene 1
.
Si todavía está confundido, sugiero experimentar con (setq b a)
y ver por sí mismo cuál de las expresiones modificar b
cuando se actúa sobre a
(los que actúan sobre el símbolo a
) y cuáles no (los que actuar sobre el valor del símbolo a
).
¿Puede decir si algo es una macro o una función puramente de su documentación sin mirar la implementación? – Tom
La documentación de @Tom generalmente indica eso inmediatamente en la primera línea (para push - 'push es una macro Lisp en \' cl.el''). –
Sí, pero ¿qué hay de setcar? ¿Cómo sabe por la documentación que no evalúa su argumento? – Tom