Respuesta corta
Omita las reglas de evaluación predeterminadas y no evalúe la expresión (símbolo o s-exp), pasándola a la función exactamente como se escribió.
Respuesta larga: la regla de evaluación predeterminada
Cuando se invoca una función regular (lo abordaré más adelante), se evalúan todos los argumentos que se le pasan. Esto significa que puede escribir esto:
(* (+ a 2)
3)
Que a su vez evalúa (+ a 2)
, evaluando a
y 2. El valor del símbolo a
se busca en el conjunto de vinculación de variables actual y luego se reemplaza. Say a
está actualmente vinculado al valor 3:
(let ((a 3))
(* (+ a 2)
3))
Obtendríamos (+ 3 2)
, luego se invoca + en 3 y 2, lo que da como resultado 5. Nuestra forma original ahora (* 5 3)
produce 15.
¡Explica quote
ya!
Bien. Como se vio anteriormente, se evalúan todos los argumentos de una función, por lo que si desea pasar el símbolo a
y no su valor, no desea evaluarlo. Los símbolos Lisp pueden duplicar sus valores y marcadores en los que en otros lenguajes habría utilizado cadenas, como claves para tablas hash.
Aquí es donde quote
entra en juego. Supongamos que desea trazar las asignaciones de recursos desde una aplicación Python, pero más bien hacer el trazado en Lisp. Haga que su aplicación Python haga algo como esto:
print("'(")
while allocating:
if random.random() > 0.5:
print(f"(allocate {random.randint(0, 20)})")
else:
print(f"(free {random.randint(0, 20)})")
...
print(")")
Dándole una salida con este aspecto (un poco bastante bonito):
'((allocate 3)
(allocate 7)
(free 14)
(allocate 19)
...)
¿Recuerda lo que dije sobre quote
("marcar") que provocó que la regla predeterminada no se aplicara? Bueno. Lo que de otro modo sucedería es que se busquen los valores de allocate
y free
, y no queremos eso. En nuestro Lisp, deseamos hacer:
(dolist (entry allocation-log)
(case (first entry)
(allocate (plot-allocation (second entry)))
(free (plot-free (second entry)))))
Para los datos proporcionados anteriormente, se habría realizado la siguiente secuencia de llamadas a funciones:
(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)
Pero ¿qué pasa list
?
Bueno, a veces tu no desea evaluar los argumentos. Digamos que tiene una función ingeniosa que manipula un número y una cadena y devuelve una lista de las ... cosas resultantes. Hagamos un comienzo en falso:
(defun mess-with (number string)
'(value-of-number (1+ number) something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))
¡Oye! Eso no es lo que queríamos. Queremos evaluar selectivamente algunos argumentos y dejar los demás como símbolos. ¡Prueba el número 2!
(defun mess-with (number string)
(list 'value-of-number (1+ number) 'something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)
No solo quote
, sinobackquote
¡Mucho mejor! Por cierto, este patrón es tan común en (en su mayoría) macros, que existe una sintaxis especial para hacer precisamente eso. La cita inversa:
(defun mess-with (number string)
`(value-of-number ,(1+ number) something-with-string ,(length string)))
Es como usar quote
, pero con la opción de evaluar explícitamente algunos argumentos añadiéndoles una coma. El resultado es equivalente a usar list
, pero si está generando código a partir de una macro, a menudo solo desea evaluar pequeñas partes del código devuelto, por lo que la cita inversa es más adecuada. Para listas más cortas, list
puede ser más legible.
Oye, te olvidaste de quote
!
¿A dónde nos lleva esto? Oh cierto, ¿qué hace quote
realmente? ¡Simplemente devuelve su (s) argumento (s) sin evaluar! ¿Recuerda lo que dije al principio sobre las funciones regulares? Resulta que algunos operadores / funciones necesitan no evalúan sus argumentos. Como SI, no querría que se evaluara la rama else si no se hubiera tomado, ¿verdad? Así llamado operadores especiales , junto con las macros, funcionan así. Los operadores especiales también son el "axioma" del lenguaje, un conjunto mínimo de reglas, sobre el que puede implementar el resto de Lisp combinándolos de diferentes maneras.
Sin quote
embargo, volviendo a:
Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL
Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL
Comparar con (en Steel-Bank Common Lisp):
Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING {A69F6A9}>:
The variable SPIFFY-SYMBOL is unbound.
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0]
Porque no hay spiffy-symbol
en el ámbito actual!
Resumiendo
quote
, backquote
(con coma), y list
son algunas de las herramientas que usa para crear listas, que no son solo listas de valores, sino que, como puede ver, pueden usarse como ligeras (no es necesario definir unstruct
estructuras de datos ).
Si desea obtener más información, le recomiendo el libro Practical Common Lisp de Peter Seibel para un enfoque práctico del aprendizaje de Lisp, si ya está interesado en la programación. Eventualmente, en su viaje Lisp, también comenzará a usar paquetes. Ron Garret's The Idiot's Guide to Common Lisp Packages le dará una buena explicación de ellos.
¡Feliz piratería!