Pregunta

Después de pasar por las partes principales de un libro introductorio de Lisp, todavía no pude entender lo que hace la función del operador especial (quote) (o equivalente ') Sin embargo, esto ha sido todo el código Lisp que he visto.

¿Qué hace?

¿Fue útil?

Solución

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 normal (veré más adelante), se evalúan todos los argumentos que se le pasan. Esto significa que puedes 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 enlace variable actual, y luego reemplazado. Diga a está actualmente vinculado al valor 3:

(let ((a 3))
  (* (+ a 2)
     3))

Obtendríamos (+ 3 2) , + luego se invoca en 3 y 2 produciendo 5. Nuestro formulario original ahora es (* 5 3) produciendo 15 .

Explique quote ¡Ya!

Está bien. Como se vio anteriormente, todos los argumentos de una función se evalúan, por lo que si desea pasar el símbolo y no su valor, no desea evaluarlo. Los símbolos Lisp pueden duplicarse tanto como sus valores como los marcadores en los que en otros idiomas habrían utilizado cadenas, como las claves para las tablas hash.

Aquí es donde entra quote . Supongamos que desea trazar las asignaciones de recursos desde una aplicación de Python, pero haga 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 bonito):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

¿Recuerda lo que dije sobre quote (" tick ") causando que la regla predeterminada no se aplique? Bueno. Lo que sucedería de otra manera es que los valores de allocate y free se consultan, 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 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 con list?

Bueno, a veces do quiere evaluar los argumentos. Digamos que tienes una función ingeniosa que manipula un número y una cadena y devuelve una lista de las ... cosas resultantes. Hagamos un falso comienzo:

(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))

Hey! Eso no es lo que queríamos. Queremos selectivamente evaluar algunos argumentos, y dejar los otros como símbolos. Intenta # 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 , sino backquote

Mucho mejor! Por cierto, este patrón es tan común en (en su mayoría) macros, que hay una sintaxis especial para hacer precisamente eso. El backquote:

(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 una coma. El resultado es equivalente al uso de 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 es más adecuado hacer una cita inversa. Para listas más cortas, list puede ser más legible.

Oye, te olvidaste de quote!

Entonces, ¿dónde nos deja esto? Oh cierto, ¿qué hace quote en realidad? 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 SI: no querrías que la rama else fuera evaluada si no fuera tomada, ¿verdad? Los llamados operadores especiales , junto con las macros, funcionan así. Los operadores especiales son también el " axioma " del lenguaje, un conjunto mínimo de reglas, sobre las cuales puede implementar el resto de Lisp combinándolos de diferentes maneras.

Volver a quote , sin embargo:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

Compare con (en Common Bankp de Steel-Bank):

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 alcance actual!

Resumiendo

quote , backquote (con comas) y list son algunas de las herramientas que usa para crear listas, que no son solo listas de valores, pero como se puede ver, se puede usar como estructuras de datos ligeras (no es necesario definir una estructura de código struct )

Si desea obtener más información, recomiendo el libro de Peter Seibel Lisp común práctico para un enfoque práctico para aprender Lisp , si ya estás en la programación en general. Finalmente, en tu viaje a Lisp, también comenzarás a usar paquetes. La Guía para idiotas de los paquetes comunes de Lisp de Ron Garret te dará una buena explicación de estos.

¡Feliz piratería!

Otros consejos

Dice " no me evalúes " ;. Por ejemplo, si desea utilizar una lista como datos y no como un código, debe poner una cita delante de ella. Por ejemplo,

(imprimir '(+ 3 4)) imprime " (+ 3 4) " ;, mientras que (imprimir (+ 3 4)) imprime " 7 "

Otras personas han respondido a esta pregunta de manera admirable, y Matthias Benkard muestra una excelente advertencia.

NO USE CITA PARA CREAR LISTAS DE MODIFICACIÓN MÁS TARDE. La especificación permite al compilador tratar las listas entre comillas como constantes. A menudo, un compilador optimizará las constantes creando un solo valor para ellas en la memoria y luego haciendo referencia a ese único valor 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, es muy posible que modifique otros usos de la misma constante en un código completamente no relacionado. Por ejemplo, puede comparar alguna variable con '(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 con '(1 1 2 3 5 8 13), que es lo que devolvió la segunda función. Estas dos funciones no están relacionadas, pero tienen un efecto mutuo debido al uso de constantes. Incluso pueden ocurrir malos efectos más locos, como una iteración de lista perfectamente normal, de repente, un bucle infinito.

Use comillas cuando necesite una lista constante, como para la comparación. Use la lista cuando vaya a modificar el resultado.

Una respuesta a esta pregunta dice que QUOTE "crea listas de estructuras de datos". Esto no está del todo bien. CITA es más fundamental que esto. De hecho, QUOTE es un operador trivial: su propósito es evitar que nada suceda en absoluto. En particular, no crea nada.

Lo que dice (QUOTE X) es básicamente "no hagas nada, solo dame X". X no necesita ser una lista como en (QUOTE (A B C)) o un símbolo como en (QUOTE FOO). Puede ser cualquier objeto cualquiera. De hecho, el resultado de evaluar la lista producida por (LISTA DE LA CITA DE ALGUNOS OBJETOS) siempre devolverá SOME-OBJECT, sea el que sea.

Ahora, la razón por la que (CITA (A B C)) parece como si creó una lista cuyos elementos son A, B y C es que tal lista es realmente lo que devuelve; pero en el momento en que se evalúa el formulario de COTIZACIÓN, la lista generalmente ya existe desde hace tiempo (¡como componente del formulario de COTIZACIÓN!), creada 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 es muy imprudente modificar una lista devuelta por un formulario de COTIZACIÓN. Los datos devueltos por QUOTE deben, para todos los propósitos, considerarse como parte del código que se está ejecutando y, por lo tanto, deben tratarse como de solo lectura.

Cuando queremos pasar un argumento en lugar de pasar el valor del argumento, entonces usamos quote. Está mayormente relacionado con el procedimiento que pasa durante el uso de listas, pares y átomos. que no están disponibles en el lenguaje de programación C (la mayoría de la gente comienza a programar utilizando la programación en C, por lo que nos confundimos) Este es el código en el lenguaje de programación Scheme, que es un dialecto de lisp y creo 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 (atom? 'abc) pasa abc como está al procedimiento para verificar si abc es un átomo o no, pero cuando pasa (atom? abc), entonces verifica el valor de abc y pasa el valor para ello. Desde entonces, no le hemos proporcionado ningún valor

En Emacs Lisp:

¿Qué se puede citar?

Listas y símbolos.

La cotización de un número se evalúa al número en sí: '5 es lo mismo que 5 .

¿Qué sucede cuando cotizas listas?

Por ejemplo:

'(uno dos) se evalúa como

(lista 'uno' dos) que se evalúa como

(lista (interno " uno ") (interno (" dos "))) .

(intern " one ") crea un símbolo llamado " one " y lo almacena en un " central " hash-map, así que cada vez que digas 'one entonces el símbolo denominado " one " se 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 nombre , que es el nombre del símbolo como " one " ; arriba, y los datos y / o el código pueden asociarse con este objeto.

Por lo tanto, 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 Y (al mismo tiempo, para el mismo símbolo) 2) código asociado: según el contexto, ya sea los datos o el código se llama .

Por ejemplo, en Elisp:

(progn
  (fset 'add '+ )
  (set 'add 2)
  (add add add)
)

evalúa a 4 .

Porque (agregar agregar agregar) se evalúa como:

(add add add)
(+ add add)
(+ 2 add)
(+ 2 2)
4

Entonces, por ejemplo, utilizando la clase Symbol que definimos en Python anteriormente, este add ELisp-Symbol podría escribirse en Python como Symbol (" añada ", (lambda x, y: x + y), 2) .

Muchas gracias por la gente en #Cemacs de IRC por explicarme los símbolos y las citas.

Quote devuelve la representación interna de sus argumentos. Después de repasar demasiadas explicaciones de lo que no hace la cita no , fue entonces cuando se encendió la bombilla. Si el REPL no convirtió los nombres de las funciones a MAYÚSCULAS cuando los cité, es posible que no se me haya ocurrido.

Entonces. Las funciones ordinarias de Lisp convierten sus argumentos en una representación interna, evalúan los argumentos y aplican la función. Quote convierte sus argumentos en una representación interna, y solo devuelve eso. Técnicamente es correcto decir que la cita dice, "no evalúes", pero cuando intentaba entender lo que hacía, decirme lo que no hace es frustrante. Mi tostadora tampoco evalúa las funciones de Lisp; pero no es así como se explica lo que hace una tostadora.

Respuesta corta de Anoter:

quote significa sin evaluarla, y backquote es quote pero deja back doors .

Una buena referencia:

El manual de referencia de Emacs Lisp lo deja muy claro

9.3 Cotización

La cita de formulario especial devuelve su único argumento, tal como está escrito, sin evaluarlo. Esto proporciona una manera 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).

Forma especial: objeto de cotización

This special form returns object, without evaluating it. 

Debido a que las comillas se usan con frecuencia en los programas, Lisp proporciona una sintaxis de lectura conveniente para ellos. Un carácter de apóstrofe (& # 8216; '& # 8217;) seguido de un objeto Lisp (en sintaxis de lectura) se expande a una lista cuyo primer elemento es cita y cuyo segundo elemento es el objeto. Por lo tanto, la sintaxis de lectura 'x es una abreviatura de (quote x).

Aquí hay algunos ejemplos de expresiones que usan comillas:

(quote (+ 1 2))
     ⇒ (+ 1 2)

(quote foo)
     ⇒ foo

'foo
     ⇒ foo

''foo
     ⇒ (quote foo)

'(quote foo)
     ⇒ (quote foo)

9.4 Backquote

Las construcciones de referencia entre comillas le permiten citar una lista, pero evaluar selectivamente los elementos de esa lista. En el caso más simple, es idéntico a la cita de formulario especial (descrita en la sección anterior; consulte Cotización). Por ejemplo, estas dos formas producen 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 & # 8216;, & # 8217; en el interior del argumento para volver a cotizar indica un valor que no es & # 8217; t constante. El evaluador de Emacs Lisp evalúa el argumento de & # 8216;, & # 8217; y coloca el valor en la estructura de la lista:

`(a list of ,(+ 2 3) elements)
     ⇒ (a list of 5 elements)

Sustitución con & # 8216;, & # 8217; está permitido en niveles más profundos de la estructura de la lista también. Por ejemplo:

`(1 2 (3 ,(+ 4 5)))
     ⇒ (1 2 (3 9))

También puede unir un valor evaluado en la lista resultante, utilizando el marcador especial & # 8216;, @ & # 8217 ;. Los elementos de la lista de empalmes se convierten en elementos al mismo nivel que los otros elementos de la lista resultante. El código equivalente sin usar & # 8216; `& # 8217; a menudo es ilegible. Aquí hay algunos 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)
Code is data and data is code.  There is no clear distinction between them.

Esta es una declaración clásica que cualquier programador de lisp conoce.

Cuando cites un código, ese código será información.

1 ]=> '(+ 2 3 4)
;Value: (+ 2 3 4)

1 ]=> (+ 2 3 4)
;Value: 9

Cuando cites un código, el resultado serán datos que representan ese código. Entonces, cuando desea trabajar con datos que representan un programa, usted cita ese programa. Esto también es válido para expresiones atómicas, no solo para listas:

1 ]=> 'code
;Value: code

1 ]=> '10
;Value: 10

1 ]=> '"ok"
;Value: "ok"

1 ]=> code
;Unbound variable: code

Suponiendo que desea crear un lenguaje de programación incrustado en lisp, trabajará con programas citados en esquema (como '(+ 2 3) ) y que se interpretan como código en el Lenguaje que creas, dando a los programas una interpretación semántica. En este caso, debe usar la cita para conservar los datos, de lo contrario, se evaluará en un idioma externo.

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