resueltos - ¿Cuándo usar ''(o citar) en Lisp?
listas en lisp ejemplos (9)
Después de pasar las partes principales de un libro introductorio de Lisp, aún no podía entender qué hace la función especial del operador (quote)
(o equivalente), pero esto ha sido todo el código Lisp que he visto.
¿Qué hace?
Cita devuelve la representación interna de sus argumentos. Después de analizar demasiadas explicaciones de lo que la cita no hace, fue entonces cuando se encendió la bombilla. Si el REPL no convirtió los nombres de las funciones en MAYÚSCULAS cuando los cité, podría no haber caído en la cuenta.
Asi que. Las funciones de Lisp ordinarias convierten sus argumentos en una representación interna, evalúan los argumentos y aplican la función. La cotización convierte sus argumentos en una representación interna, y solo devuelve eso. Técnicamente, es correcto decir que la cita dice "no evaluar", pero cuando intentaba entender lo que hacía, decirme lo que no funcionaba era frustrante. Mi tostadora tampoco evalúa las funciones de Lisp; pero no es así como explicas lo que hace una tostadora.
Cuando queremos pasar un argumento en sí mismo en lugar de pasar el valor del argumento, usamos quote. Está principalmente relacionado con el procedimiento que pasa durante el uso de listas, pares y átomos que no están disponibles en lenguaje de programación C (la mayoría de las personas comienzan a programar usando programación C, por lo tanto nos confundimos). Este es el código del lenguaje de programación Scheme que es un dialecto de ceceo y supongo que puedes entender este código.
(define atom? ; defining a procedure atom?
(lambda (x) ; which as one argument x
(and (not (null? x)) (not(pair? x) )))) ; checks if the argument is atom or not
(atom? ''(a b c)) ; since it is a list it is false #f
La última línea (átomo? ''Abc) está pasando abc como está al procedimiento para comprobar si abc es un átomo o no, pero cuando pasas (atom? Abc) luego verifica el valor de abc y pasa el valor a eso. Desde entonces, no le hemos dado ningún valor
Dice "no me evalúes". Por ejemplo, si quisiera utilizar una lista como datos, y no como código, colocaría una cita delante de ella. Por ejemplo,
(print ''(+ 3 4))
imprime "(+ 3 4)", mientras que (print (+ 3 4))
imprime "7"
La cita impide la ejecución o evaluación de un formulario, convirtiéndolo en datos. En general, puede ejecutar los datos al evaluarlos.
cita crea estructuras de datos de lista, por ejemplo, los siguientes son equivalentes:
(quote a)
''a
También se puede usar para crear listas (o árboles):
(quote (1 2 3))
''(1 2 3)
Probablemente sea mejor que obtenga un libro introductorio sobre lisp, como Practical Common Lisp (que está disponible para leer en línea).
Otras personas han respondido admirablemente a esta pregunta, y Matthias Benkard presenta una excelente advertencia.
NO UTILICE LA COTIZACIÓN PARA CREAR LISTAS QUE DESPUÉS MODIFICARÁ. La especificación permite que el compilador trate las listas citadas como constantes. A menudo, un compilador optimizará las constantes creando un solo valor para ellas en la memoria y luego haciendo referencia a ese valor único desde todas las ubicaciones donde aparece la constante. En otras palabras, puede tratar la constante como una variable global anónima.
Esto puede causar problemas obvios. Si modifica una constante, puede muy bien modificar otros usos de la misma constante en un código completamente no relacionado. Por ejemplo, puede comparar alguna variable a ''(1 1) en alguna función, y en una función completamente diferente, comenzar una lista con'' (1 1) y luego agregarle más cosas. Al ejecutar estas funciones, es posible que la primera función ya no coincida con las cosas correctamente, porque ahora está tratando de comparar la variable a ''(1 1 2 3 5 8 13), que es lo que devuelve la segunda función. Estas dos funciones no están relacionadas por completo, pero tienen un efecto el uno sobre el otro debido al uso de constantes. Incluso pueden ocurrir malos efectos más locos, como una iteración de lista perfectamente normal de repente bucle infinito.
Use comillas cuando necesite una lista constante, como por ejemplo para comparar. Use la lista cuando va a modificar el resultado.
Una respuesta a esta pregunta dice que QUOTE "crea estructuras de datos de listas". Esto no es del todo correcto. CITA es más fundamental que esto. De hecho, QUOTE es un operador trivial: su propósito es evitar que suceda nada. En particular, no crea nada.
Lo que (QUOTE X) dice es básicamente "no hagas nada, solo dame X". X no necesita ser una lista como en (QUOTE (ABC)) o un símbolo como en (QUOTE FOO). Puede ser cualquier objeto lo que sea. De hecho, el resultado de evaluar la lista producida por (LIST ''QUOTE SOME-OBJECT) siempre devolverá SOME-OBJECT, sea lo que sea.
Ahora, la razón por la cual (QUOTE (ABC)) parece que creó una lista cuyos elementos son A, B y C es que tal lista realmente es lo que devuelve; pero en el momento en que se evalúa el formulario QUOTE, la lista generalmente ya existe desde hace un tiempo (como un componente del formulario QUOTE!), creado por el cargador o el lector antes de la ejecución del código.
Una consecuencia de esto que tiende a hacer tropezar a los novatos con bastante frecuencia es que no es muy inteligente modificar una lista devuelta por un formulario QUOTE. ¡Los datos devueltos por QUOTE se consideran, a todos los efectos, como parte del código que se está ejecutando y, por lo tanto, deben tratarse como de solo lectura!
En Emacs Lisp:
¿Qué se puede citar?
Listas y símbolos
Citar un número evalúa al número mismo: ''5
es lo mismo que 5
.
¿Qué pasa cuando citas listas?
Por ejemplo:
''(one two)
evalúa
(list ''one ''two)
que evalúa
(list (intern "one") (intern ("two")))
.
(intern "one")
crea un símbolo llamado "uno" y lo almacena en un "hash-map" central, por lo que cada vez que diga ''one
, el símbolo llamado "one"
buscará en ese hash-map central.
Pero, ¿qué es un símbolo?
Por ejemplo, en OO-languages (Java / Javascript / Python) un símbolo podría representarse como un objeto que tiene un campo de name
, que es el nombre del símbolo como "one"
arriba, y los datos y / o el código pueden asociarse con él este objeto
Entonces un símbolo en Python podría implementarse como:
class Symbol:
def __init__(self,name,code,value):
self.name=name
self.code=code
self.value=value
En Emacs Lisp, por ejemplo, un símbolo puede tener 1) datos asociados con él Y (al mismo tiempo, para el mismo símbolo) 2) código asociado: según el contexto, se llama a los datos o al código.
Por ejemplo, en Elisp:
(progn
(fset ''add ''+ )
(set ''add 2)
(add add add)
)
evalúa a 4
.
Porque (add add add)
evalúa como:
(add add add)
(+ add add)
(+ 2 add)
(+ 2 2)
4
Entonces, por ejemplo, usando la clase Symbol
que definimos en Python arriba, este add
ELisp-Symbol podría escribirse en Python como Symbol("add",(lambda x,y: x+y),2)
.
Muchas gracias a la gente en IRC #emacs por explicarme símbolos y citas.
Respuesta corta de Anoter:
quote
significa sin evaluarlo, y backquote es quote pero deja atrás las puertas .
Una buena referencia:
El manual de referencia de Emacs Lisp lo deja muy claro
9.3 Citando
La oferta de formulario especial devuelve su único argumento, tal como está escrito, sin evaluarlo. Esto proporciona una forma de incluir símbolos y listas constantes, que no son objetos de autoevaluación, en un programa. (No es necesario citar objetos de autoevaluación como números, cadenas y vectores).
Formulario especial: objeto de cotización
This special form returns object, without evaluating it.
Como la cita se utiliza con tanta frecuencia en los programas, Lisp proporciona una sintaxis de lectura conveniente para ella. Un carácter de apóstrofo ('''' '') seguido de un objeto Lisp (en sintaxis de lectura) se expande a una lista cuyo primer elemento es comillas, y cuyo segundo elemento es el objeto. Por lo tanto, la sintaxis de lectura ''x es una abreviatura de (cita x).
Aquí hay algunos ejemplos de expresiones que usan quote:
(quote (+ 1 2))
⇒ (+ 1 2)
(quote foo)
⇒ foo
''foo
⇒ foo
''''foo
⇒ (quote foo)
''(quote foo)
⇒ (quote foo)
9.4 Backquote
Las construcciones de Backquote le permiten citar una lista, pero evalúan selectivamente los elementos de esa lista. En el caso más simple, es idéntica a la cita de forma especial (descrita en la sección anterior, vea Citas). Por ejemplo, estas dos formas arrojan resultados idénticos:
`(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
''(a list of (+ 2 3) elements)
⇒ (a list of (+ 2 3) elements)
El marcador especial '','' dentro del argumento para hacer una comilla inversa indica un valor que no es constante. El evaluador de Emacs Lisp evalúa el argumento de '','' y coloca el valor en la estructura de la lista:
`(a list of ,(+ 2 3) elements)
⇒ (a list of 5 elements)
La sustitución con '','' también está permitida en niveles más profundos de la estructura de la lista. Por ejemplo:
`(1 2 (3 ,(+ 4 5)))
⇒ (1 2 (3 9))
También puede empalmar un valor evaluado en la lista resultante, usando el marcador especial '', @''. Los elementos de la lista empalmada se convierten en elementos al mismo nivel que los otros elementos de la lista resultante. El código equivalente sin usar '''' ''a menudo no se puede leer. Aquí hay unos ejemplos:
(setq some-list ''(2 3))
⇒ (2 3)
(cons 1 (append some-list ''(4) some-list))
⇒ (1 2 3 4 2 3)
`(1 ,@some-list 4 ,@some-list)
⇒ (1 2 3 4 2 3)
Respuesta corta Evite 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 escribe.
Respuesta larga: la regla de evaluación predeterminada
Cuando se invoca una función regular (pasaré a la siguiente), se evalúan todos los argumentos que se le pasan. Esto significa que puedes escribir esto:
(* (+ a 2)
3)
A su vez, evalúa (+ a 2)
, evaluando a
y 2. El valor del símbolo a
se busca en el conjunto de enlace de variable actual, y luego se reemplaza. Say a
está actualmente vinculado al valor 3:
(let ((a 3))
(* (+ a 2)
3))
Obtendremos (+ 3 2)
, + luego se invoca en 3 y 2 rindiendo 5. Nuestra forma original es ahora (* 5 3)
produciendo 15.
Explicar la quote
¡Ya!
Bien. Como se vio anteriormente, se evalúan todos los argumentos de una función, por lo tanto, si desea pasar el símbolo a
y no su valor, no desea evaluarlo. Los símbolos Lisp pueden duplicar tanto como sus valores, y los marcadores donde usted en otros idiomas habría usado cadenas, como las claves de las tablas hash.
Aquí es donde aparece la quote
. Supongamos que desea trazar las asignaciones de recursos desde una aplicación de Python, pero en lugar de hacer el trazado en Lisp. Haga que su aplicación Python haga algo como esto:
print "''("
while allocating:
if random.random() > 0.5:
print "(allocate %d)" random.randint(0, 20)
else:
print "(free %d)" % random.randint(0, 20)
...
print ")"
Te da salida con un aspecto como este (ligeramente bello):
''((allocate 3)
(allocate 7)
(free 14)
(allocate 19)
...)
¿Recuerda lo que dije sobre la quote
("tic") que hace que la regla predeterminada no se aplique? Bueno. Lo que sucedería de otra manera es que los valores de allocate
y free
son buscados, y no queremos eso. En nuestro Lisp, queremos hacer:
(dolist (entry allocation-log)
(case (first entry)
(allocate (plot-allocation (second entry)))
(free (plot-free (second entry)))))
Para los datos indicados 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 con la list
?
Bueno, a veces quieres evaluar los argumentos. Digamos que tiene una función ingeniosa manipulando un número y una cadena y devolviendo una lista de las ... cosas resultantes. Hagamos un comienzo 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 otros como símbolos. Prueba el # 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 una quote
, sino una quote
backquote
¡Mucho mejor! Incidentemente, este patrón es tan común en (principalmente) macros, que hay una sintaxis especial para hacer exactamente eso. La cita hacia atrás:
(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 prefijándolos con comas. El resultado es equivalente a usar la list
, pero si está generando código a partir de una macro, a menudo solo desea evaluar partes pequeñas del código devuelto, por lo que la cita posterior es más adecuada. Para listas más cortas, la list
puede ser más legible.
¡Oye, te olvidaste de la quote
!
¿A dónde nos lleva esto? Ah, claro, ¿qué es lo que realmente hace la quote
? ¡Simplemente devuelve su (s) argumento (s) sin evaluar! ¿Recuerdas lo que dije al principio sobre las funciones regulares? Resulta que algunos operadores / funciones necesitan no evaluar sus argumentos. Como IF: no querría que se evaluara la rama else si no se tomaba, ¿verdad? Los llamados 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 las cuales puede implementar el resto de Lisp combinándolos de diferentes maneras.
De vuelta a la quote
, sin embargo:
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 ningún spiffy-symbol
en el alcance actual!
Resumiendo
quote
, backquote
(con coma), y list
son algunas de las herramientas que utiliza para crear listas, que no son solo listas de valores, sino que, como puede ver, se pueden utilizar como struct
datos livianas (sin necesidad de definir una struct
).
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 en general. Eventualmente en su viaje de Lisp, también comenzará a usar paquetes. La guía de idiotas de Ron Garret sobre los paquetes de Common Lisp le dará una buena explicación de ellos.
¡Feliz hacking!