2013-04-30 11 views
50

Zastanawiam się, jaka jest różnica między tymi operacjami. Widziałem podobne pytania w Stack Overflow, ale dotyczą one Lisp i nie ma porównania między trzema z tych operatorów. Jeśli więc zostało to już zadane, proszę dać mi znać.Jaka jest różnica między eq ?, eqv ?, równa ?, i = w Scheme?

piszę różne rodzaje poleceń na schemacie, a ja się następujące wyjścia:

(eq? 5 5) -->#t 
(eq? 2.5 2.5) -->#f 
(equal? 2.5 2.5) --> #t 
(= 2.5 2.5) --> #t 

Może ktoś wyjaśnić, dlaczego tak jest?

+1

i istnieje również "eqv?", Co oznacza coś innego niż "eq?" Lub "equal?" – newacct

Odpowiedz

95

Odpowiem na to pytanie stopniowo. Zacznijmy od predykatu równoważności =. Predykat = służy do sprawdzania, czy dwie liczby są równe. Jeśli podasz mu nic innego, jak wiele to będzie podnieść błąd:

(= 2 3)  => #f 
(= 2.5 2.5) => #t 
(= '() '()) => error 

eq? orzecznikiem jest używany w celu sprawdzenia, czy jej dwa parametry respresent tego samego obiektu w pamięci.Na przykład:

(define x '(2 3)) 
(define y '(2 3)) 
(eq? x y)   => #f 
(define y x) 
(eq? x y)   => #t 

Należy jednak pamiętać, że istnieje tylko jedna pusta lista '() w pamięci (właściwie pusta lista nie istnieje w pamięci, ale wskaźnik do lokalizacji pamięci 0 jest uważana za pustą listę). Dlatego przy porównywaniu pustych list eq? zawsze zwróci #t (ponieważ reprezentują one ten sam obiekt w pamięci):

(define x '()) 
(define y '()) 
(eq? x y)  => #t 

Teraz w zależności od implementacji eq? mogą lub nie mogą wrócić #t dla wartości pierwotnych, takich jak liczby, ciągi, etc Na przykład:

(eq? 2 2)  => depends upon the implementation 
(eq? "a" "a") => depends upon the implementation 

Tutaj pojawia się predykat eqv?. Numer eqv? jest dokładnie taki sam, jak predykatu eq?, z tym że zawsze będzie zwracał #t dla tych samych wartości pierwotnych. Na przykład:

(eqv? 2 2)  => #t 
(eqv? "a" "a") => depends upon the implementation 

Stąd eqv? jest rozszerzeniem eq? i w większości przypadków należy użyć eqv? zamiast eq?.

Wreszcie dochodzimy do predykatu equal?. Predykat equal? jest dokładnie taki sam jak predykat eqv?, z tym wyjątkiem, że można go również użyć do sprawdzenia, czy dwie listy, wektory itp. Mają odpowiednie elementy, które spełniają predykat eqv?. Na przykład:

(define x '(2 3)) 
(define y '(2 3)) 
(equal? x y)  => #t 
(eqv? x y)  => #f 

ogólnie:

  1. Użyj = orzecznik gdy chcesz sprawdzić, czy dwie liczby są równoważne.
  2. Użyj predykatu eqv?, aby przetestować, czy dwie wartości nieliczbowe są równoważne.
  3. Użyj predykatu equal?, aby sprawdzić, czy dwie listy, wektory itp. Są równoważne.
  4. Nie używaj predykatu eq?, chyba że wiesz dokładnie, co robisz.
+6

AFAIK '(eqv?" A "" a ") ==> nieokreślone". Będziesz musiał użyć 'równego?' Lub (prawdopodobnie bardziej zoptymalizowanego) 'string =?' – Sylwester

+2

według [Raportu] (http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs- ZH-9.html #% _ idx_216), '(eq? '(1)' (1))' jest * nieokreślone *, więc twoja ilustracja '(define x '(1 2)) może nie działać. –

+1

+1 dla ogólnych zaleceń. – ceving

4

Nie wspominacie o implementacji schematu, ale w Przekrętce, eq? zwraca tylko wartość true, jeśli argumenty odnoszą się do tego samego obiektu. Twój drugi przykład daje #f, ponieważ system tworzy nową liczbę zmiennoprzecinkową dla każdego argumentu; nie są tym samym obiektem.

equal? i = sprawdzają równoważność wartości, ale = dotyczy tylko numerów.

Jeśli używasz rakiety, sprawdź numer here, aby uzyskać więcej informacji. W przeciwnym razie sprawdź dokumentację wdrożenia twojego systemu.

+3

Lepiej jeszcze ... Przeczytaj specyfikację ... http://www.r6rs.org/final/html /r6rs/r6rs-ZH-14.html#node_sec_11.5 – Dirk

10

W specyfikacji RNRS znajdują się pełne dwie strony związane z eq?, eqv?, equal? and =. Oto Draft R7RS Specification. Sprawdź to!

Objaśnienie:

  • = porównuje liczby, 2,5 i 2,5 są takie same.
  • equal? dla liczb zmniejsza się do =, 2,5 i 2,5 są numerycznie równe.
  • eq? porównuje "wskaźniki". Liczba 5, w realizacji twojego Planu, jest realizowana jako "natychmiastowa" (prawdopodobnie), zatem 5 i 5 są identyczne. Liczba 2.5 może wymagać przydziału "rekordu zmiennoprzecinkowego" w implementacji Schematu, dwa wskaźniki nie są identyczne.
+1

Link do wersji roboczej specyfikacji R7RS jest martwy od 2018-02-04 –

+1

Zaktualizowany do linku na żywo. – GoZoner

5

equal? rekursywnie porównuje dwa obiekty (dowolnego typu) dla równości.

  • Uwaga to może być kosztowne dla dużej struktury danych ponieważ potencjalnie całej listy, sznurka, wektor, etc musi zostać wykonany ruch.

  • Jeśli obiekt zawiera tylko jeden element (EG: numer, znak itp.), Jest taki sam jak eqv?.


eqv? testuje dwa obiekty, w celu określenia, czy oba „normalnie uważane za tego samego obiektu.”

  • eqv? i eq? są bardzo podobne operacje, a różnice między nimi będą nieco realizacja specyficzny.

eq? jest taka sama jak eqv? ale może być w stanie dostrzec bardziej subtelnych różnic, i mogą być realizowane bardziej efektywnie.

  • Według specyfikacji, to może być realizowane jako szybki i skuteczny porównania wskaźnik, w przeciwieństwie do bardziej skomplikowanych operacji na eqv?.


= porównuje numery równości liczbowej.

  • Zauważ, że więcej niż dwa numery mogą być dostarczone, np: (= 1 1.0 1/1 2/2)
+0

Myślałem, że "eq?" Było rzeczywistym wskaźnikiem równości (nie "eqv?"). Jest to "najwspanialszy lub najbardziej dyskryminujący". Na przykład. '(eqv? 2 2)' jest gwarantowane jako '# t', ale' (eq? 2 2) 'jest" nieokreślone ". To znaczy. zależy to od tego, czy implementacja tworzy rzeczywisty nowy obiekt pamięci dla każdej nowo odczytanej liczby, czy też ponownie wykorzystuje poprzednio utworzoną, jeśli może. –

+0

@WillNess - Dobry połów, dzięki. Różnice między 'eq?' I 'eqv?' Są bardziej subtelne niż inne operacje. –

3

Pomyśl eq? jak równość wskaźnika. Twórcy modelu Report chcą, aby był on jak najbardziej ogólny, więc nie mówią tego wprost, ponieważ jest on zależny od implementacji i, mówiąc to, sprzyjałby implementacjom opartym na wskaźnikach. Ale oni mówią:

It will usually be possible to implement eq? much more efficiently than eqv?, for example, as a simple pointer comparison

Oto co mam na myśli. (eqv? 2 2) z gwarancją zwrotu #t, ale (eq? 2 2) jest nieokreślona. Teraz wyobraź sobie implementację opartą na wskaźnikach. W nim eq? jest po prostu porównanie wskaźnika. Ponieważ (eq? 2 2) jest bliżej nieokreślone, oznacza to, że ta implementacja umożliwia utworzenie nowej reprezentacji obiektu pamięci dla każdego nowego numeru, który odczytuje z kodu źródłowego. eqv? musi faktycznie sprawdzić jego argumenty.

OTOH (eq 'a 'a) to #t. Oznacza to, że taka implementacja musi rozpoznawać symbole o zduplikowanych nazwach i używać tego samego obiektu reprezentacji w pamięci dla wszystkich z nich.

Załóżmy, że implementacja nie opiera się na wskaźnikach. Dopóki jest ono zgodne z Raportem, nie ma to znaczenia. Autorzy po prostu nie chcą być postrzegani jako dyktujący specyfikę implementacji dla realizatorów, więc starannie dobierają swoje sformułowania.

To jest moje przypuszczenie w każdym razie.

Tak bardzo grubo, eq? jest równość wskaźnik, eqv? jest (atomic-) Wartości-Aware, equal? jest również struktura-aware (kontrole na swoich argumentów rekurencyjnie, tak że w końcu (equal? '(a) '(a)) ma obowiązek być #t), = jest dla numery, string=? jest dla ciągów, a szczegóły są w raporcie.

6

eq? jest #t gdy jest to ten sam adres/przedmiot. Zwykle można oczekiwać #t dla tego samego symbolu, wartości logicznej i obiektu oraz #f dla wartości innego typu, z różnymi wartościami lub bez tej samej struktury. Schematy/implementacje Lisp mają tradycję wbudowywania typów w ich wskaźniki i osadzać wartości w tej samej przestrzeni, jeśli jest wystarczająco dużo miejsca. Tak więc niektóre wskaźniki naprawdę nie są adresami, ale wartościami, takimi jak char R lub Fixnum 10. Będą to eq?, ponieważ "adres" jest osadzonym typem + wartością. Niektóre implementacje również wykorzystują stałe stałe. (eq? '(1 2 3)' (1 2 3)) może być #f podczas interpretacji, ale #t podczas kompilacji, ponieważ może uzyskać ten sam adres. (Podobnie jak stała pula String w Javie). Z tego powodu wiele nieporozumień dotyczących eq? jest nieokreślonych, a zatem liczba oceniana jako #t lub #f zależy od implementacji.

eqv? są #tybyły tak samo jak eq?.Jest to również # t, jeśli jest to liczba lub znak, a jego wartość jest taka sama, nawet jeśli dane są zbyt duże, aby zmieścić się w wskaźniku. Tak więc dla tych eqv? dodatkowa praca sprawdzania tego typu jest jedną z obsługiwanych, oba są tego samego typu, a jej obiekty docelowe mają tę samą wartość danych.

equal? jest #t do tych samych rzeczy jak eqv? i jeśli jest to typ związek jak pary, wektor, sznurka i bytevector to rekurencyjnie robi equal? z częściami. W praktyce zwróci #t, jeśli oba obiekty wyglądają tak samo. Przed R6RS nie jest bezpieczne używanie equal? w strukturach kołowych.

= jest jak eqv? ale to działa tylko dla typów liczbowych. To może być bardziej wydajne.

string=? jest jak equal?, ale działa tylko na smyczki. To może być bardziej wydajne.

Powiązane problemy