scheme - moon - bloodstained: ritual of the night plataformas
¿Cuál es la diferencia entre quote y list? (1)
TL; DR: son diferentes;
use la
list
cuando tenga dudas.
Una regla general: use la
list
siempre que desee que se evalúen los argumentos;
quote
"distribuye" sobre sus argumentos, por lo que
''(+ 1 2)
es como
(list ''+ ''1 ''2)
.
Terminarás con un símbolo en tu lista, no una función.
Una mirada en profundidad a la
list
y
quote
En Scheme and Racket,
quote
y
list
son
cosas completamente diferentes
, pero dado que ambos se pueden usar para producir listas, la confusión es común y comprensible.
Hay una diferencia increíblemente importante entre ellos: la
list
es una
función
antigua simple, mientras que la
quote
(incluso sin la sintaxis especial) es una
forma especial
.
Es decir, la
list
se puede implementar en un esquema simple, pero la
quote
no se puede implementar.
La función de
list
La función de
list
es en realidad la más simple de las dos, así que comencemos allí.
Es una función que toma cualquier número de argumentos y los recoge en una lista.
> (list 1 2 3)
(1 2 3)
Este ejemplo anterior puede ser confuso porque el resultado se imprime como una s-expresión entre
quote
, y es cierto, en este caso, las dos sintaxis son equivalentes.
Pero si nos volvemos un poco más complicados, verá que es diferente:
> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> ''(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
¿Qué está pasando en el ejemplo de la
quote
?
Bueno, discutiremos eso en un momento, pero primero, eche un vistazo a la
list
.
Es solo una función ordinaria, por lo que sigue la semántica de evaluación de Scheme estándar: evalúa cada uno de sus argumentos
antes de
pasarlos a la función.
Esto significa que expresiones como
(+ 1 1)
se reducirán a
2
antes de que se recopilen en la lista.
Este comportamiento también es visible al suministrar variables a la función de lista:
> (define x 42)
> (list x)
(42)
> ''(x)
(x)
Con la
list
, la
x
se evalúa antes de pasar a la
list
.
Con
quote
, las cosas son más complicadas.
Finalmente, debido a que
list
es solo una función, se puede usar como cualquier otra función, incluso en formas de orden superior.
Por ejemplo, se puede pasar a la función de
map
y funcionará adecuadamente:
> (map list ''(1 2 3) ''(4 5 6))
((1 4) (2 5) (3 6))
El formulario de
quote
La cita, a diferencia de la
list
, es una parte especial de Lisps.
El formulario de
quote
es especial en parte porque tiene una abreviatura de lector especial
''
, pero también es especial incluso sin eso.
A diferencia de la
list
, la
quote
no
es una función y, por lo tanto, no necesita comportarse como tal, tiene sus propias reglas.
Una breve discusión del código fuente de Lisp
En Lisp, de los cuales Scheme y Racket son derivados, todo el código está hecho de estructuras de datos ordinarias. Por ejemplo, considere la siguiente expresión:
(+ 1 2)
Esa expresión es en realidad una lista , y tiene tres elementos:
-
el símbolo
+
-
el numero
1
-
el numero
2
Todos estos valores son valores normales que el programador puede crear.
Es realmente fácil crear el valor
1
porque se evalúa a sí mismo: solo escribe
1
.
Pero los símbolos y las listas son más difíciles: por defecto, ¡un símbolo en el código fuente realiza una búsqueda variable!
Es decir, los símbolos no
se autoevalúan
:
> 1
1
> a
a: undefined
cannot reference undefined identifier
Sin embargo, los símbolos son básicamente cadenas y, de hecho, podemos convertirlos entre ellos:
> (string->symbol "a")
a
¡Las listas hacen incluso más que símbolos, porque por defecto, una lista en el código fuente
llama a una función!
Hacer
(+ 1 2)
mira el primer elemento de la lista, el símbolo
+
, busca la función asociada a él y lo invoca con el resto de los elementos de la lista.
A veces, sin embargo, es posible que desee deshabilitar este comportamiento "especial".
Es posible que desee obtener la lista u obtener el símbolo sin que se evalúe.
Para hacer esto, puede usar
quote
.
El significado de la cita
Con todo esto en mente, es bastante obvio lo que hace la
quote
: simplemente "desactiva" el comportamiento de evaluación especial para la expresión que envuelve.
Por ejemplo, considere
quote
un símbolo:
> (quote a)
a
Del mismo modo, considere
quote
una lista:
> (quote (a b c))
(a b c)
No importa lo que
quote
, siempre,
siempre lo
escupirá.
Ni mas ni menos.
Eso significa que si le da una lista, ninguna de las subexpresiones será evaluada, ¡no espere que lo sean!
Si necesita una evaluación de algún tipo, use la
list
.
Ahora, uno podría preguntarse: ¿qué sucede si
quote
algo que no sea un símbolo o una lista?
Bueno, la respuesta es ... ¡nada!
Solo lo recuperas.
> (quote 1)
1
> (quote "abcd")
"abcd"
Esto tiene sentido, ya que la
quote
todavía solo escupe exactamente lo que le das.
Esta es la razón por la cual los "literales", como los números y las cadenas, a veces se denominan "autocomillas" en el lenguaje Lisp.
Una cosa más: ¿qué sucede si
quote
una expresión que contiene
quote
?
Es decir, ¿qué pasa si usted "
quote
dos
quote
"?
> (quote (quote 3))
''3
¿Que paso ahi?
Bueno, recuerde que
''
realidad es solo una abreviatura directa de
quote
, ¡así que no pasó nada especial!
De hecho, si su Esquema tiene una forma de deshabilitar las abreviaturas al imprimir, se verá así:
> (quote (quote 3))
(quote 3)
No se deje engañar por la
quote
es especial: al igual que
(quote (+ 1))
, el resultado aquí es simplemente una lista antigua.
De hecho, podemos sacar el primer elemento de la lista: ¿puedes adivinar cuál será?
> (car (quote (quote 3)))
quote
Si adivinaste
3
, estás equivocado.
Recuerde,
quote
deshabilita
toda evaluación
, y una expresión que contiene un símbolo de
quote
sigue siendo solo una lista simple.
Juega con esto en el REPL hasta que te sientas cómodo con él.
> (quote (quote (quote 3)))
''''3
(quote (1 2 (quote 3)))
(1 2 ''3)
La cita es increíblemente simple, pero puede resultar muy compleja debido a que tiende a desafiar nuestra comprensión del modelo de evaluación tradicional. De hecho, es confuso debido a lo simple que es: no hay casos especiales, no hay reglas. Simplemente devuelve exactamente lo que le da, exactamente como se indica (de ahí el nombre "cita").
Apéndice A: Cuasiquotación
Entonces, si la cita inhabilita por completo la evaluación, ¿para qué sirve? Bueno, aparte de hacer listas de cadenas, símbolos o números que se conocen con anticipación, no mucho. Afortunadamente, el concepto de cuasiquotación proporciona una forma de salir de la cita y volver a la evaluación ordinaria.
Los conceptos básicos son súper simples: en lugar de usar
quote
, use
quasiquote
.
Normalmente, esto funciona exactamente como una
quote
en todos los sentidos:
> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))
Lo que hace que la
quasiquote
sea especial es que reconoce un símbolo especial,
unquote
.
Dondequiera que aparezca una
unquote
en la lista, entonces se reemplaza por la expresión arbitraria que contiene:
> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
Esto le permite usar
quasiquote
para construir plantillas de tipo que tengan "agujeros" para rellenar con
unquote
.
Esto significa que es posible incluir los valores de las variables dentro de las listas citadas:
> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
Por supuesto, usar
quasiquote
y
unquote
es bastante detallado, por lo que tienen abreviaturas propias, al igual que
''
.
Específicamente,
quasiquote
es
`
(retroceso) y sin
unquote
es (coma).
Con esas abreviaturas, el ejemplo anterior es mucho más apetecible.
> `(x is: ,x)
(x is: 42)
Un último punto: la cuasiquota en realidad
se
puede implementar en Racket usando una macro bastante peluda, y lo es.
Se expande a usos de
list
,
cons
y, por supuesto,
quote
.
Apéndice B: Implementación de
list
y
quote
en Esquema
La implementación de la
list
es súper simple debido a cómo funciona la sintaxis de "argumento de descanso".
Esto es todo lo que necesitas:
(define (list . args)
args)
¡Eso es!
En contraste, la
quote
es mucho más difícil, de hecho, ¡es imposible!
Parecería totalmente factible, ya que la idea de deshabilitar la evaluación se parece mucho a las macros.
Sin embargo, un intento ingenuo revela el problema:
(define fake-quote
(syntax-rules ()
((_ arg) arg)))
Simplemente tomamos
arg
y lo volvemos a escupir ... pero esto no funciona.
Por qué no?
Bueno, se evaluará el resultado de nuestra macro, por lo que todo es en vano.
Es posible que podamos expandirnos a algo así como una
quote
expandiéndonos a
(list ...)
y citando recursivamente los elementos, así:
(define impostor-quote
(syntax-rules ()
((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
((_ (e ...)) (list (impostor-quote e) ...))
((_ x) x)))
Sin embargo, desafortunadamente, sin macros de procedimiento, no podemos manejar símbolos sin
quote
.
Podríamos acercarnos usando
syntax-case
, pero incluso así, solo estaríamos emulando el comportamiento de la
quote
, no replicando.
Apéndice C: Convenciones de impresión de raquetas
Al probar los ejemplos en esta respuesta en Racket, es posible que no se impriman como cabría esperar.
A menudo, pueden imprimir con un encabezado
''
, como en este ejemplo:
> (list 1 2 3)
''(1 2 3)
Esto se debe a que Racket, de forma predeterminada, imprime los resultados como expresiones cuando es posible.
Es decir, debe poder escribir el resultado en REPL y recuperar el mismo valor.
Personalmente, considero que este comportamiento es agradable, pero puede ser confuso al tratar de comprender la cita, por lo que si desea desactivarlo, llame
(print-as-expression #f)
o cambie el estilo de impresión a "escribir" en DrRacket menú de idiomas
Sé que puedes usar
''
(también conocido como
quote
) para crear una lista, y lo uso todo el tiempo, así:
> (car ''(1 2 3))
1
Pero no siempre funciona como esperaba. Por ejemplo, intenté crear una lista de funciones, como esta, pero no funcionó:
> (define math-fns ''(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
expected a procedure that can be applied to arguments
given: ''+
Cuando uso la
list
, funciona:
> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
''(1 -1 1 1)
¿Por qué?
Pensé
''
era solo una taquigrafía conveniente, entonces, ¿por qué es diferente el comportamiento?