В чем разница между эквалайзером?- экв?- равны?, а = в схеме?


интересно, в чем разница между этими операциями. Я видел подобные вопросы в Stack Overflow, но они касаются Lisp, и нет сравнения между тремя из этих операторов. Поэтому, если это уже было задано, пожалуйста, дайте мне знать.

Я пишу различные типы команд в схему, и я получаю следующие результаты:

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

может кто-нибудь объяснить, почему это так?

6 53

6 ответов:

я отвечу на этот вопрос постепенно. Давайте начнем с = эквивалентности предиката. Элемент = предикат используется для проверки того, равны ли два числа. Если вы поставите ему что-нибудь еще, кроме числа, то он вызовет ошибку:

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

The eq? предикат используется для проверки того, соответствуют ли два его параметра одному и тому же объекту в памяти. Например:

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

обратите внимание, однако, что есть только один пустой список '() в память (на самом деле пустой список не существует в памяти, но указатель на ячейку памяти 0 считается пустым списком). Следовательно, при сравнении пустых списков eq? всегда будет возвращать #t (потому что они представляют один и тот же объект в памяти):

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

теперь в зависимости от реализации eq? может или не может возвращать #t для примитивных значений, таких как числа, строки и т. д. Например:

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

вот тут eqv? сказуемое входит в картину. Элемент eqv? точно так же, как eq? предикат, за исключением того, что он всегда будет возвращать #t для тех же примитивных значений. Например:

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

отсюда eqv? - это надмножество eq? и в большинстве случаев вы должны использовать eqv? вместо eq?.

наконец-то мы подошли к equal? сказуемое. Элемент equal? предикат точно такой же, как eqv? сказуемое, за исключением того, что он также может быть использован для проверки два списка, векторы и т. д. есть соответствующие элементы, которые удовлетворяют eqv? сказуемое. Например:

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

в общем:

  1. использовать = предикат, когда вы хотите проверить, эквивалентны ли два числа.
  2. использовать eqv? предикат, если вы хотите проверить, эквивалентны ли два нечисловых значения.
  3. использовать equal? предикат, когда вы хотите проверить, есть ли два списка, векторы и т. д. являются аналог.
  4. не используйте eq? предикат, если вы точно не знаете, что вы делаете.

в спецификации RNRS есть полные две страницы, связанные с eq?, eqv?, equal? and =. Вот это проект спецификации R7RS. Зацени!

пояснение:

  • = сравнивает числа, 2.5 и 2.5 численно равны.
  • equal? для чисел уменьшается до =, 2.5 и 2.5 численно равны.
  • eq? сравнивает 'указатели'. Число 5, в вашей реализации схемы, реализуется как "немедленное" (вероятно), что 5 и 5 идентичны. Число 2.5 может потребовать выделения "записи с плавающей запятой" в вашей реализации схемы, два указателя не идентичны.

eq? и #t когда это тот же адрес/объект. обычно можно ожидать #t для одного и того же символа, булева и объекта и #f для значений разного типа, с разными значениями или не одной и той же структурой Scheme / Lisp-реализации имеют традицию вставлять тип в свои указатели и вставлять значения в одно и то же пространство, если этого достаточно. Таким образом, некоторые указатели на самом деле не адреса, а значения, такие как char R или Fixnum 10. Это будет eq? Так как "адрес" является встроенным типом+значение. Некоторые реализации также повторно используют неизменяемые константы. (эквалайзер? '(1 2 3) '(1 2 3)) может быть #f при интерпретации, но #t при компиляции, так как он может получить тот же адрес. (Как постоянный пул строк в Java). Из-за этого многие выражения с участием eq? не указаны, таким образом, если он оценивает #t или #f зависит от реализации.

eqv? are #t для тех же вещей, что и eq?. Это также #t, если это число или символ, и это значение то же самое, даже если данные слишком велики, чтобы поместиться в указатель. Таким образом, для тех eqv? делает дополнительную работу по проверке того, что тип является одним из поддерживаемых, что оба являются одним и тем же типом, и его целевые объекты имеют одно и то же значение данных.

equal? это #t для тех же вещей, что и eqv? и если это сложный тип, как пара, вектор, строка, и bytevector это рекурсивно делает equal? С части. на практике он вернет #t, если два объекта выглядят одинаково. До R6RS, это небезопасно использовать equal? на кольцевые структуры.

= как eqv? но это работает только для числовых типов. Это может быть более эффективным.

string=? как equal?, а это работает только для строк. это может быть более эффективным.

equal? рекурсивно сравнивает два объекта (любого типа) для равенства.

  • обратите внимание, это может быть дорого для большой структуры данных с потенциально весь список, строка, вектор и т. д. Необходимо пройти.

  • если объект содержит только один элемент (например, число, символ и т. д.), Это так же, как eqv?.


eqv? проверяет два объекта, чтобы определить, если оба "обычно рассматривается как один и тот же объект".

  • eqv? и eq? очень похожи операции, и различия между ними будут несколько специфичны для реализации.

eq? это то же самое, что eqv? но может быть способен различать более тонкие различия и может быть реализован более эффективно.

  • согласно спецификации, это может быть реализовано как быстрое и эффективное сравнение указателей, в отличие от к более сложной операции для eqv?.


= сравнивает числа для числового равенства.
  • обратите внимание, что может быть предоставлено более двух чисел, например:(= 1 1.0 1/1 2/2)

вы не упоминаете реализацию схемы, но в рэкете,eq? возвращает true только в том случае, если аргументы ссылаются на один и тот же объект. Ваш второй пример дает #f, потому что система создает новое число с плавающей запятой для каждого аргумента; они не являются одним и тем же объектом.

equal? и = проверяют эквивалентность значений, но = применимо только к номерам.

если вы используете ракетку, проверить здесь для получения дополнительной информации. В противном случае проверьте документацию по реализации схемы.

думать eq? как равенство указателей. Авторы отчет хочу, чтобы это было как можно более общим, поэтому они не говорят об этом прямо, потому что это зависит от реализации, и сказать это, будет способствовать реализации на основе указателя. Но они говорят

обычно можно будет реализовать эквалайзер? гораздо эффективнее, чем эквалайзер? например , как простой указатель сравнения

вот что я имею в виду. (eqv? 2 2) is гарантированный возврат #t но (eq? 2 2) является неуказанным. Теперь представьте себе реализацию на основе указателя. В нем eq? Это просто сравнение указателей. Так как (eq? 2 2) не указано, это означает, что эта реализация может просто создавать новое представление объекта памяти каждого нового числа, которое он читает из исходного кода. eqv? должны проверять свои аргументы.

OTOH (eq 'a 'a) и #t. Это означает, что такая реализация должна распознавать символы с одинаковыми именами и использовать то же самое один представление объекта в памяти для всех из них.

предположим, что реализация не на основе указателя. Пока это соответствует отчету, это не имеет значения. Авторы просто не хотят, чтобы их видели диктующими специфику реализаций разработчикам, поэтому они тщательно выбирают свою формулировку.

это моя догадка в любом случае.

очень крупно, eq? равенство указателя, eqv? is (atomic-)values-aware, equal? также осознает структуру (рекурсивно проверяет свои аргументы, так что, наконец,(equal? '(a) '(a)) требуется #t),= для чисел string=? для строк и данные в отчете.