Ich frage mich, was der Unterschied zwischen diesen Operationen in Schema ist. Ich habe ähnliche Fragen in Stack Overflow gesehen, aber es geht um Lisp, und es gibt keinen Vergleich zwischen drei dieser Operatoren.
Ich schreibe die verschiedenen Arten von Befehlen in Schema und erhalte die folgenden Ausgaben:
(eq? 5 5) -->#t
(eq? 2.5 2.5) -->#f
(equal? 2.5 2.5) --> #t
(= 2.5 2.5) --> #t
Warum ist das so?
functional-programming
scheme
yrazlik
quelle
quelle
eqv?
, was etwas anderes bedeutet alseq?
oderequal?
Antworten:
Ich werde diese Frage schrittweise beantworten. Beginnen wir mit dem
=
Äquivalenzprädikat. Das=
Prädikat wird verwendet, um zu überprüfen, ob zwei Zahlen gleich sind. Wenn Sie etwas anderes als eine Nummer angeben, wird ein Fehler ausgegeben:(= 2 3) => #f (= 2.5 2.5) => #t (= '() '()) => error
Das
eq?
Prädikat wird verwendet, um zu überprüfen, ob seine beiden Parameter dasselbe Objekt im Speicher darstellen. Zum Beispiel:(define x '(2 3)) (define y '(2 3)) (eq? x y) => #f (define y x) (eq? x y) => #t
Beachten Sie jedoch, dass sich nur eine leere Liste
'()
im Speicher befindet (tatsächlich existiert die leere Liste nicht im Speicher, aber ein Zeiger auf den Speicherort0
wird als leere Liste betrachtet). Daher werden beim Vergleich leerer Listeneq?
immer zurückgegeben#t
(da sie dasselbe Objekt im Speicher darstellen):(define x '()) (define y '()) (eq? x y) => #t
Abhängig von der Implementierung
eq?
kann nun#t
für primitive Werte wie Zahlen, Zeichenfolgen usw. zurückgegeben werden oder nicht . Zum Beispiel:(eq? 2 2) => depends upon the implementation (eq? "a" "a") => depends upon the implementation
Hier kommt das
eqv?
Prädikat ins Spiel. Daseqv?
ist genau das gleiche wie daseq?
Prädikat, außer dass es immer#t
für dieselben primitiven Werte zurückgibt. Zum Beispiel:(eqv? 2 2) => #t (eqv? "a" "a") => depends upon the implementation
Daher
eqv?
ist eine Obermenge voneq?
und für die meisten Fälle sollten Sieeqv?
anstelle von verwendeneq?
.Schließlich kommen wir zum
equal?
Prädikat. Dasequal?
Prädikat ist genau das gleiche wie daseqv?
Prädikat, außer dass es auch verwendet werden kann, um zu testen, ob zwei Listen, Vektoren usw. entsprechende Elemente haben, die daseqv?
Prädikat erfüllen . Zum Beispiel:(define x '(2 3)) (define y '(2 3)) (equal? x y) => #t (eqv? x y) => #f
Im Allgemeinen:
=
Prädikat, wenn Sie testen möchten, ob zwei Zahlen gleichwertig sind.eqv?
Prädikat, wenn Sie testen möchten, ob zwei nicht numerische Werte äquivalent sind.equal?
Prädikat, wenn Sie testen möchten, ob zwei Listen, Vektoren usw. gleichwertig sind.eq?
Prädikat nur, wenn Sie genau wissen, was Sie tun.quelle
(eqv? "a" "a") ==> unspecified
. Sie müssen verwendenequal?
oder (die möglicherweise optimierte)string=?
(eq? '(1) '(1))
ist nicht spezifiziert , so dass Ihre(define x '(1 2))
Darstellung funktionieren kann nicht.(eq? 'foo 'foo) -> #t
,(eq? 'foo 'bar)
-> false`. Ich habe das hier und hierDie RnRS-Spezifikation enthält zwei vollständige Seiten
eq?, eqv?, equal? and =
. Hier ist der Entwurf der R7RS-Spezifikation . Hör zu!Erläuterung:
=
vergleicht Zahlen, 2.5 und 2.5 sind numerisch gleich.equal?
für Zahlen reduziert sich auf=
2.5 und 2.5 sind numerisch gleich.eq?
vergleicht 'Zeiger'. Die Nummer 5 in Ihrer Schema-Implementierung wird als "sofort" (wahrscheinlich) implementiert, daher sind 5 und 5 identisch. Die Zahl 2.5 erfordert möglicherweise die Zuweisung eines 'Gleitkomma-Datensatzes' in Ihrer Schema-Implementierung. Die beiden Zeiger sind nicht identisch.quelle
eq?
ist,#t
wenn es die gleiche Adresse / das gleiche Objekt ist. Normalerweise kann man erwarten, dass #t für dasselbe Symbol, denselben Booleschen Wert und dasselbe Objekt und #f für Werte unterschiedlichen Typs, mit unterschiedlichen Werten oder nicht derselben Struktur verwendet wird. Schema- / Lisp-Implementierungen haben die Tradition, Typen in ihre Zeiger einzubetten und einzubetten Werte im selben Raum, wenn genügend Platz vorhanden ist. Daher sind einige Zeiger wirklich keine Adressen, sondern Werte wieR
das Zeichen oder das Fixnum10
. Dieseq?
geschieht , da die "Adresse" ein eingebetteter Typ + Wert ist. Einige Implementierungen verwenden auch unveränderliche Konstanten wieder. (eq? '(1 2 3)' (1 2 3)) könnte bei der Interpretation #f sein, beim Kompilieren jedoch #t, da es möglicherweise dieselbe Adresse erhält. (Wie der konstante String-Pool in Java). Aus diesem Grund sind viele Ausdrücke involvierteq?
sind nicht spezifiziert, daher ist es implementierungsabhängig, ob es als #t oder #f ausgewertet wird.eqv?
sind #t für die gleichen Dinge wieeq?
. Es ist auch #t, wenn es sich um eine Zahl oder ein Zeichen handelt und der Wert gleich ist , selbst wenn die Daten zu groß sind, um in einen Zeiger zu passen. Für dieseeqv?
bedeutet die zusätzliche Arbeit, zu überprüfen, ob dieser Typ einer der unterstützten ist, dass beide vom selben Typ sind und die Zielobjekte den gleichen Datenwert haben.equal?
ist #t für die gleichen Dinge wieeqv?
und wenn es sich um einen zusammengesetzten Typ wie Paar, Vektor, Zeichenfolge und Bytevektor handelt, wird dies rekursivequal?
mit den Teilen durchgeführt. In der Praxis wird #t zurückgegeben, wenn die beiden Objekte gleich aussehen . Vor R6RS ist die Verwendungequal?
in kreisförmigen Strukturen nicht sicher .=
ist wie,eqv?
aber es funktioniert nur für numerische Typen . Es könnte effizienter sein.string=?
ist wieequal?
, aber es funktioniert nur für Strings. Es könnte effizienter sein.quelle
equal?
vergleicht rekursiv zwei Objekte (eines beliebigen Typs) auf Gleichheit.Beachten Sie, dass dies für eine große Datenstruktur teuer sein kann, da möglicherweise die gesamte Liste, Zeichenfolge, der Vektor usw. durchlaufen werden muss.
Wenn das Objekt nur ein einzelnes Element enthält (z
eqv?
. B. Nummer, Zeichen usw.), ist dies dasselbe wie .eqv?
testet zwei Objekte, um festzustellen, ob beide "normalerweise als dasselbe Objekt angesehen werden".eqv?
undeq?
sind sehr ähnliche Operationen, und die Unterschiede zwischen ihnen werden etwas implementierungsspezifisch sein.eq?
ist das Gleiche wieeqv?
, kann jedoch feinere Unterscheidungen erkennen und kann effizienter implementiert werden.eqv?
.=
vergleicht Zahlen auf numerische Gleichheit.(= 1 1.0 1/1 2/2)
quelle
eq?
es wäre tatsächliche Zeigergleichheit (nichteqv?
). Es ist "das Beste oder Diskriminierendste". ZB(eqv? 2 2)
ist garantiert#t
, aber(eq? 2 2)
"nicht spezifiziert". Das heißt, es hängt davon ab, ob eine Implementierung für jede neu gelesene Nummer ein tatsächlich neues Speicherobjekt erstellt oder ein zuvor erstelltes Objekt wiederverwendet, wenn dies möglich ist.eq?
undeqv?
sind subtiler als die anderen Operationen.Sie erwähnen keine Schemaimplementierung, geben jedoch in Racket
eq?
nur true zurück, wenn sich die Argumente auf dasselbe Objekt beziehen. Ihr zweites Beispiel liefert #f, da das System für jedes Argument eine neue Gleitkommazahl erstellt. Sie sind nicht dasselbe Objekt.equal?
und=
prüfen auf Wertäquivalenz, gelten jedoch=
nur für Zahlen.Wenn Sie Racket verwenden, finden Sie hier weitere Informationen. Überprüfen Sie andernfalls die Dokumentation Ihrer Schemaimplementierung.
quelle
Stellen Sie sich
eq?
Zeigergleichheit vor. Die Autoren des Berichts möchten, dass er so allgemein wie möglich ist, damit sie dies nicht direkt sagen, da er implementierungsabhängig ist und die zeigerbasierten Implementierungen bevorzugen würde. Aber sie sagenHier ist was ich meine.
(eqv? 2 2)
wird garantiert zurückkehren#t
,(eq? 2 2)
ist aber nicht spezifiziert. Stellen Sie sich nun eine zeigerbasierte Implementierung vor. Darineq?
ist nur ein Zeigervergleich. Da dies(eq? 2 2)
nicht angegeben ist, bedeutet dies, dass diese Implementierung nur eine neue Speicherobjektdarstellung für jede neue Nummer erstellen kann, die sie aus dem Quellcode liest.eqv?
muss tatsächlich seine Argumente überprüfen.OTOH
(eq 'a 'a)
ist#t
. Dies bedeutet , dass ein solche Umsetzung Symbole mit doppelten Namen erkennen muß und das gleiche verwendet eine Darstellung Objekt im Speicher für alle von ihnen.Angenommen, eine Implementierung basiert nicht auf Zeigern. Solange es sich an den Bericht hält, spielt es keine Rolle. Die Autoren möchten einfach nicht so gesehen werden, dass sie den Implementierern die Besonderheiten der Implementierungen diktieren, deshalb wählen sie ihren Wortlaut sorgfältig aus.
Das ist sowieso meine Vermutung.
So sehr grob,
eq?
isteqv?
Zeigergleichheit , ist (atomar-) wertebewusst,equal?
ist auch strukturbewusst (prüft seine Argumente rekursiv, so dass es schließlich(equal? '(a) '(a))
erforderlich ist#t
),=
ist für Zahlen,string=?
ist für Zeichenfolgen und die Details sind im Bericht.quelle
Abgesehen von den vorherigen Antworten werde ich einige Kommentare hinzufügen.
Alle diese Prädikate möchten die abstrakte Funktion
identity
eines Objekts definieren, jedoch in unterschiedlichen Kontexten.EQ?
ist implementierungsabhängig und beantwortet die Frage nichtare 2 objects the same?
nur in begrenztem Umfang. Aus Sicht der Implementierung vergleicht dieses Prädikat nur 2 Zahlen (Zeiger auf Objekte), es betrachtet nicht den Inhalt der Objekte. Wenn Ihre Implementierung beispielsweise die Zeichenfolgen nicht eindeutig enthält, sondern für jede Zeichenfolge einen anderen Speicher reserviert, ist(eq? "a" "a")
dies falsch.EQV?
- Dies sieht in die Objekte, aber mit begrenzter Verwendung. Es ist implementierungsabhängig, wenn es true für zurückgibt(eqv? (lambda(x) x) (lambda(x) x))
. Hier ist eine vollständige Philosophie, wie dieses Prädikat definiert wird, da wir heutzutage wissen, dass es einige schnelle Methoden gibt, um die Funktionalität einiger Funktionen mit begrenzter Verwendung zu vergleichen.eqv?
Bietet aber eine kohärente Antwort für große Zahlen, Zeichenfolgen usw.In der Praxis versuchen einige dieser Prädikate, die abstrakte Definition eines Objekts (mathematisch) zu verwenden, während andere die Darstellung eines Objekts verwenden (wie es auf einer realen Maschine implementiert ist). Die mathematische Definition von Identität stammt von Leibniz und lautet:
X = Y iff for any P, P(X) = P(Y) X, Y being objects and P being any property associated with object X and Y.
Idealerweise wäre es möglich, genau diese Definition auf einem Computer zu implementieren, aber aus Gründen der Unentschlossenheit und / oder Geschwindigkeit wird sie nicht wörtlich implementiert. Aus diesem Grund gibt es viele Operatoren, die versuchen, sich auf unterschiedliche Gesichtspunkte rund um diese Definition zu konzentrieren.
Versuchen Sie sich die abstrakte Definition einer Identität für eine Fortsetzung vorzustellen. Selbst wenn Sie eine Definition einer Teilmenge von Funktionen ( Sigma-rekursive Funktionsklasse ) bereitstellen können, legt die Sprache kein Prädikat fest, das wahr oder falsch ist. Dies würde sowohl die Definition der Sprache als auch die Implementierung erheblich erschweren.
Der Kontext für die anderen Prädikate ist einfacher zu analysieren.
quelle