functional-programming - que - scheme programing language
¿Cuál es la diferencia entre eq ?, eqv ?, equal ?, y=in Scheme? (6)
Me pregunto cuál es la diferencia entre esas operaciones. He visto preguntas similares en Stack Overflow pero se trata de Lisp, y no hay una comparación entre tres de esos operadores. Entonces, si esto ya se ha preguntado, házmelo saber.
Escribo los diferentes tipos de comandos en Scheme y obtengo los siguientes resultados:
(eq? 5 5) -->#t
(eq? 2.5 2.5) -->#f
(equal? 2.5 2.5) --> #t
(= 2.5 2.5) --> #t
¿Alguien puede explicar por qué es este el caso?
¿No menciona una implementación de esquema, pero en Racket, eq?
solo devuelve verdadero si los argumentos se refieren al mismo objeto. Su segundo ejemplo arroja #f porque el sistema está creando un nuevo número de coma flotante para cada argumento; ellos no son el mismo objeto
equal?
y =
están comprobando la equivalencia del valor, pero =
solo es aplicable a los números.
Si está usando Racket, mire here para más información. De lo contrario, verifique la documentación de la implementación de su esquema.
Hay dos páginas completas en la especificación RNRS relacionadas con eq?, eqv?, equal? and =
eq?, eqv?, equal? and =
Aquí está la Especificación Draft R7RS . ¡Echale un vistazo!
Explicación:
-
=
compara números, 2.5 y 2.5 son numéricamente iguales. -
equal?
para los números se reduce a=
, 2.5 y 2.5 son numéricamente iguales. -
eq?
compara ''punteros''. El número 5, en la implementación de su Esquema, se implementa como ''inmediato'' (probable), por lo tanto, 5 y 5 son idénticos. El número 2.5 puede requerir una asignación de un "registro de coma flotante" en la implementación del Esquema, los dos indicadores no son idénticos.
Piensa en eq?
como puntero de igualdad. Los autores del Informe quieren que sea lo más general posible, por lo que no lo dicen directamente porque depende de la implementación, y decirlo, favorecería las implementaciones basadas en punteros. Pero ellos dicen
Por lo general, será posible implementar eq? de manera mucho más eficiente que eqv ?, por ejemplo, como una comparación de puntero simple
Esto es lo que quiero decir. (eqv? 2 2)
se garantiza que devolverá #t
pero (eq? 2 2)
no está especificado. Ahora imagina una implementación basada en punteros. En eso eq?
es solo una comparación de puntero. Dado que (eq? 2 2)
no está especificado, significa que esta implementación es libre de simplemente crear una nueva representación de objeto de memoria de cada nuevo número que lee desde el código fuente. eqv?
debe realmente inspeccionar sus argumentos.
OTOH (eq ''a ''a)
es #t
. Esto significa que dicha implementación debe reconocer símbolos con nombres duplicados y usar el mismo objeto de representación en memoria para todos ellos.
Supongamos que una implementación no está basada en punteros. Mientras se adhiera al Informe, no importa. Los autores simplemente no quieren que se les vea dictando los detalles de las implementaciones a los implementadores, por lo que eligen cuidadosamente su redacción.
Esta es mi suposición de todos modos.
Muy groseramente, eq?
es la igualdad del puntero, eqv?
es (atómico-) consciente de los valores, equal?
también es consciente de la estructura (verifica sus argumentos recursivamente, de modo que finalmente (equal? ''(a) ''(a))
se requiere que sea #t
), =
es para números, string=?
es para cadenas, y los detalles están en el Informe.
Responderé esta pregunta de forma incremental. Comencemos con el =
predicado de equivalencia. El predicado =
se usa para verificar si dos números son iguales. Si le proporciona algo más que un número, generará un error:
(= 2 3) => #f
(= 2.5 2.5) => #t
(= ''() ''()) => error
El eq?
predicado se usa para verificar si sus dos parámetros respresentan el mismo objeto en la memoria. Por ejemplo:
(define x ''(2 3))
(define y ''(2 3))
(eq? x y) => #f
(define y x)
(eq? x y) => #t
Sin embargo, tenga en cuenta que solo hay una lista vacía ''()
en la memoria (en realidad, la lista vacía no existe en la memoria, pero un puntero a la ubicación de la memoria 0
se considera como la lista vacía). Por lo tanto, al comparar listas vacías eq?
siempre devolverá #t
(porque representan el mismo objeto en la memoria):
(define x ''())
(define y ''())
(eq? x y) => #t
Ahora dependiendo de la implementación eq?
puede o no devolver #t
para valores primitivos como números, cadenas, etc. Por ejemplo:
(eq? 2 2) => depends upon the implementation
(eq? "a" "a") => depends upon the implementation
Aquí es donde el eqv?
predicado entra en la imagen. El eqv?
es exactamente lo mismo que la eq?
predicado, excepto que siempre devolverá #t
para los mismos valores primitivos. Por ejemplo:
(eqv? 2 2) => #t
(eqv? "a" "a") => depends upon the implementation
Por eqv?
tanto eqv?
es un superconjunto de eq?
y para la mayoría de los casos debes usar eqv?
en lugar de eq?
.
Finalmente llegamos a la equal?
predicado. ¿El equal?
predicado es exactamente lo mismo que el eqv?
predicado, excepto que también se puede usar para probar si dos listas, vectores, etc. tienen elementos correspondientes que satisfacen la eqv?
predicado. Por ejemplo:
(define x ''(2 3))
(define y ''(2 3))
(equal? x y) => #t
(eqv? x y) => #f
En general:
- Use el predicado
=
cuando desee probar si dos números son equivalentes. - Use el
eqv?
predicado cuando desea probar si dos valores no numéricos son equivalentes. - Usa el
equal?
predicado cuando desea probar si dos listas, vectores, etc. son equivalentes. - No use la
eq?
predicado a menos que sepa exactamente lo que está haciendo.
equal?
recursivamente compara dos objetos (de cualquier tipo) para la igualdad.
Tenga en cuenta que esto podría ser costoso para una gran estructura de datos ya que potencialmente se debe atravesar toda la lista, cadena, vector, etc.
Si el objeto solo contiene un elemento único (por ejemplo, número, carácter, etc.), esto es lo mismo que
eqv?
.
eqv?
prueba dos objetos para determinar si ambos son "normalmente considerados como el mismo objeto".
-
eqv?
yeq?
son operaciones muy similares, y las diferencias entre ellas van a ser algo específicas de implementación.
eq?
es lo mismo que eqv?
pero puede ser capaz de discernir distinciones más finas, y puede implementarse de manera más eficiente.
- De acuerdo con la especificación, esto podría implementarse como una comparación de puntero rápida y eficiente, a diferencia de una operación más complicada para
eqv?
.
=
compara números para la igualdad numérica. - Tenga en cuenta que se pueden proporcionar más de dos números, por ejemplo:
(= 1 1.0 1/1 2/2)
eq?
es #t
cuando es la misma dirección / objeto. Normalmente uno podría esperar #t para el mismo símbolo, booleano y objeto y #f para valores que son de tipo diferente, con valores diferentes, o no tienen la misma estructura . Las implementaciones de Scheme / Lisp tienen una tradición para incrustar el tipo en sus punteros y para incrustar valores en el mismo espacio si es suficiente espacio. Por lo tanto, algunos punteros realmente no son direcciones sino valores, como el char R
o el Fixnum 10
. Estos serán eq?
ya que la "dirección" es un tipo incrustado + valor. Algunas implementaciones también reutilizan constantes inmutables. (eq? ''(1 2 3)'' (1 2 3)) podría ser #f cuando se interpreta, pero #t cuando se compila, ya que podría obtener la misma dirección. (Como el conjunto de cadenas constante en Java). Debido a esto, muchas expresiones que involucran eq?
no se especifican, por lo tanto, si se evalúa como #t o #f depende de la implementación.
eqv?
son #t para las mismas cosas que eq?
. También es #t si se trata de un número o carácter y su valor es el mismo , incluso cuando los datos son demasiado grandes para caber en un puntero. Por lo tanto, para aquellos eqv?
El trabajo adicional de verificar ese tipo es uno de los admitidos, que ambos son del mismo tipo y sus objetos objetivo tienen el mismo valor de datos.
equal?
es #t para las mismas cosas que eqv?
y si se trata de un compuesto como par, vector, cuerda y bytevector, recursivamente hace lo equal?
con las partes. En la práctica, devolverá #t si los dos objetos tienen el mismo aspecto . Antes de R6RS, no es seguro usar equal?
en estructuras circulares.
=
es como eqv?
pero solo funciona para tipos numéricos . Puede ser más eficiente.
string=?
es como equal?
, pero solo funciona para cadenas. Puede ser más eficiente.