в чем разница между eq ?, eqv ?, равно? и = в схеме?

<p>интересно, в чем разница между этими операциями. я видел подобные вопросы в stack overflow, но они касаются lisp, и между этими тремя операторами нет сравнения. так что, если об этом уже спрашивали, пожалуйста, дайте мне знать.</p><p>я пишу различные типы команд на схеме, и я получаю следующие выводы:</p><pre><code>(eq? 5 5) -->#t (eq? 2.5 2.5) -->#f (equal? 2.5 2.5) --> #t (= 2.5 2.5) --> #t </code></pre><p>может кто-нибудь объяснить, почему это так?</p>

<p>я отвечу на этот вопрос постепенно. давайте начнем с предиката эквивалентности <code>=</code>. предикат <code>=</code> используется для проверки, равны ли два числа. если вы предоставите ему что-нибудь еще, кроме числа, это вызовет ошибку:</p><pre><code>(= 2 3) => #f (= 2.5 2.5) => #t (= '() '()) => error </code></pre><p>предикат <code>eq?</code> используется для проверки того, представляют ли два его параметра один и тот же объект в памяти. например:</p><pre><code>(define x '(2 3)) (define y '(2 3)) (eq? x y) => #f (define y x) (eq? x y) => #t </code></pre><p>однако обратите внимание, что в памяти есть только один пустой список <code>'()</code> (на самом деле пустой список не существует в памяти, но указатель на ячейку памяти <code>0</code> считается пустым списком). следовательно, при сравнении пустых списков <code>eq?</code> всегда будет возвращать <code>#t</code> (потому что они представляют один и тот же объект в памяти):</p><pre><code>(define x '()) (define y '()) (eq? x y) => #t </code></pre><p>теперь в зависимости от реализации <code>eq?</code> может возвращать или не возвращать <code>#t</code> для примитивных значений, таких как числа, строки и т.д. например:</p><pre><code>(eq? 2 2) => depends upon the implementation (eq? "a" "a") => depends upon the implementation </code></pre><p>это где предикат <code>eqv?</code> входит в картину. код <code>eqv?</code> точно такой же, как и предикат <code>eq?</code>, за исключением того, что он всегда будет возвращать <code>#t</code> для тех же самых примитивных значений. например:</p><pre><code>(eqv? 2 2) => #t (eqv? "a" "a") => depends upon the implementation </code></pre><p>следовательно, <code>eqv?</code> является расширенным набором <code>eq?</code>, и в большинстве случаев вы должны использовать <code>eqv?</code> вместо <code>eq?</code>.</p><p>наконец, мы подошли к предикату <code>equal?</code>. предикат <code>equal?</code> точно такой же, как и предикат <code>eqv?</code>, за исключением того, что его также можно использовать для проверки наличия в двух списках, векторах и т.д. соответствующих элементов, которые удовлетворяют предикату <code>eqv?</code>. например:</p><pre><code>(define x '(2 3)) (define y '(2 3)) (equal? x y) => #t (eqv? x y) => #f </code></pre><p>в общем:</p><ol> <li>используйте предикат <code>=</code>, когда вы хотите проверить, эквивалентны ли два числа.</li> <li>используйте предикат <code>eqv?</code>, когда вы хотите проверить, эквивалентны ли два нечисловых значения.</li> <li>используйте предикат <code>equal?</code>, когда вы хотите проверить, эквивалентны ли два списка, вектора и т.д.</li> <li>не используйте предикат <code>eq?</code>, если точно не знаете, что делаете.</li> </ol>

<p>в спецификации rnrs есть две полные страницы, связанные с <code>eq?, eqv?, equal? and =</code>. вот <a href="http://www.larcenists.org/documentation/documentation0.98/r7rs.pdf">проект спецификации r7rs</a> . проверьте это!</p><p>объяснение:</p><ul> <li><code>=</code> сравнивает числа, 2.5 и 2.5 численно равны.</li> <li><code>equal?</code> для чисел уменьшается до <code>=</code>, 2.5 и 2.5 численно равны.</li> <li><code>eq?</code> сравнивает "указатели". число 5 в вашей реализации схемы реализовано как "немедленное" (вероятно), поэтому 5 и 5 идентичны. число 2.5 может потребовать выделения "записи с плавающей запятой" в вашей реализации схемы, эти два указателя не идентичны.</li> </ul>

<p><strong><code>eq?</code></strong> - это <code>#t</code>, когда это тот же адрес/объект. <strong>обычно можно ожидать #t для одного и того же символа, логического значения и объекта и #f для значений другого типа, с разными значениями или с разной структурой</strong> реализация схем/lisp имеет традицию встраивания введите их указатели и вставьте значения в одном и том же месте, если места достаточно. таким образом, некоторые указатели действительно являются не адресами, а значениями, такими как char <code>r</code> или fixnum <code>10</code>. это будет <code>eq?</code>, так как "адрес" - это встроенный тип + значение. некоторые реализации также повторно используют неизменные константы. (eq? '(1 2 3)' (1 2 3)) может быть #f при интерпретации, но #t при компиляции, так как он может получить тот же адрес. (как постоянный пул строк в java). из-за этого многие выражения, включающие <code>eq?</code>, не определены, поэтому, если он оценивается как #t или #f, зависит от реализации.</p><p><strong><code>eqv?</code> = #t для тех же вещей, что и <code>eq?</code>. это также #t, если это число или символ и его значение одинаковое</strong>, даже если данные слишком велики, чтобы поместиться в указатель. таким образом, для этих <code>eqv?</code> выполняется дополнительная проверка того, что этот тип является одним из поддерживаемых, что оба имеют одинаковый тип, а его целевые объекты имеют одинаковое значение данных.</p><p><strong><code>equal?</code></strong> - это #t для тех же вещей, что и <code>eqv?</code>, и если это составной тип, такой как pair, vector, string и bytevector, он рекурсивно выполняет <code>equal?</code> с частями. <strong>на практике он вернет #t, если два объекта выглядят одинаково</strong>. до r6rs небезопасно использовать <code>equal?</code> на круговых структурах.</p><p><strong><code>=</code></strong> похож на <code>eqv?</code>, но <strong>работает только для числовых типов</strong>. это может быть более эффективным.</p><p><strong><code>string=?</code></strong> похож на <code>equal?</code>, но <strong>работает только для строк.</strong> возможно, он более эффективен.</p>

<p>вы не упоминаете реализацию схемы, но в racket <code>eq?</code> возвращает true, только если аргументы ссылаются на один и тот же объект. ваш второй пример дает #f, потому что система создает новое число с плавающей запятой для каждого аргумента; они не тот же объект.</p><p><code>equal?</code> и <code>=</code> проверяют эквивалентность значений, но <code>=</code> применим только к числам.</p><p>если вы используете racket, проверьте <a href="http://docs.racket-lang.org/reference/booleans.html">здесь</a> для получения дополнительной информации. в противном случае, проверьте документацию вашей схемы реализации.</p>

<p>думайте о <code>eq?</code> как о равенстве указателей. авторы <a href="http://www.schemers.org/documents/standards/r5rs/html/r5rs-z-h-9.html#%\_idx\_216">report</a> хотят, чтобы он был как можно более общим, поэтому они не говорят этого прямо, потому что он зависит от реализации, и, скажем так, предпочтет реализации на основе указателей. но они говорят</p><blockquote> <p>обычно будет возможно реализовать эк? гораздо эффективнее, чем eqv ?, например, в качестве простого сравнения указателей</p> </blockquote><p>вот что я имею в виду. <code>(eqv? 2 2)</code> гарантированно вернет <code>#t</code>, но <code>(eq? 2 2)</code> не указан. теперь представьте реализацию на основе указателя. в нем <code>eq?</code> - это просто сравнение указателей. поскольку <code>(eq? 2 2)</code> не указан, это означает, что эта реализация может просто создавать новое представление объекта памяти для каждого нового числа, которое оно считывает из исходного кода. <code>eqv?</code> должен фактически проверить свои аргументы.</p><p>otoh <code>(eq 'a 'a)</code> - это <code>#t</code>. это означает, что такая реализация должна распознавать символы с повторяющимися именами и использовать один <em> один </em> объект представления в памяти для всех них.</p><p>предположим, что реализация не основана на указателе. пока это придерживается отчета, это не имеет значения. авторы просто не хотят, чтобы их диктовали специфике реализаций разработчикам, поэтому они тщательно выбирают свою формулировку.</p><p>в любом случае, это мое предположение.</p><p>очень грубо, <code>eq?</code> - это равенство указателей, <code>eqv?</code> - (atomic-), учитывает значения, <code>equal?</code> также учитывает структуру (рекурсивно проверяет свои аргументы, так что, наконец, <code>(equal? '(a) '(a))</code> должен быть <code>#t</code>), <code>=</code> для чисел, <code>string=?</code> - это для строк, а подробности в отчете.</p>