Интересно, в чем разница между этими операциями в схеме. Я видел похожие вопросы в Stack Overflow, но они касаются Lisp, и нет сравнения между тремя из этих операторов.
Я пишу различные типы команд на схеме и получаю следующие результаты:
(eq? 5 5) -->#t
(eq? 2.5 2.5) -->#f
(equal? 2.5 2.5) --> #t
(= 2.5 2.5) --> #t
Почему это так?
functional-programming
scheme
иразлик
источник
источник
eqv?
, что означает нечто отличное отeq?
илиequal?
Ответы:
Я отвечу на этот вопрос постепенно. Начнем с
=
предиката эквивалентности.=
Предикат используется для проверки , являются ли два числа равны. Если вы укажете что-либо еще, кроме числа, это вызовет ошибку:(= 2 3) => #f (= 2.5 2.5) => #t (= '() '()) => error
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
В общем:
=
предикат, если хотите проверить, эквивалентны ли два числа.eqv?
предикат, если хотите проверить, эквивалентны ли два нечисловых значения.equal?
предикат, если хотите проверить, эквивалентны ли два списка, вектора и т. Д.eq?
предикат, если вы точно не знаете, что делаете.источник
(eqv? "a" "a") ==> unspecified
. Вам придется использоватьequal?
или (возможно, более оптимизированный)string=?
(eq? '(1) '(1))
не указан , поэтому ваша(define x '(1 2))
иллюстрация может не работать.(eq? 'foo 'foo) -> #t
,(eq? 'foo 'bar)
-> false`. Я читал это здесь и здесьВ спецификации 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 имеют традицию встраивать тип в свои указатели и значения в том же пространстве, если его достаточно. Таким образом, некоторые указатели на самом деле являются не адресами, а значениями, такими как charR
или Fixnum10
. Это будет,eq?
поскольку «адрес» - это встроенный тип + значение. Некоторые реализации также повторно используют неизменяемые константы. (eq? '(1 2 3)' (1 2 3)) может быть #f при интерпретации, но #t при компиляции, так как он может получить тот же адрес. (Как постоянный пул строк в Java). Из-за этого многие выражения с участиемeq?
не указаны, поэтому его оценка как #t или #f зависит от реализации.eqv?
#t для тех же вещей, что иeq?
. Это также #t, если это число или символ и его значение одинаково , даже если данные слишком велики, чтобы поместиться в указатель. Таким образом, для нихeqv?
выполняется дополнительная работа по проверке того, является ли тип одним из поддерживаемых, что оба являются одним и тем же типом, и что целевые объекты имеют одинаковое значение данных.equal?
- это #t для тех же вещей, чтоeqv?
и для составного типа, такого как пара, вектор, строка и байтовый вектор, он рекурсивно обрабатываетequal?
части. На практике он вернет #t, если два объекта выглядят одинаково . До R6RS было небезопасно использоватьequal?
на круглых конструкциях.=
похоже,eqv?
но работает только для числовых типов . Это могло быть более эффективно.string=?
вродеequal?
, но работает только для струнных. Это могло быть более эффективно.источник
equal?
рекурсивно сравнивает два объекта (любого типа) на равенство.Обратите внимание, что это может быть дорогостоящим для большой структуры данных, поскольку потенциально необходимо пройти весь список, строку, вектор и т. Д.
Если объект содержит только один элемент (например, число, символ и т. Д.), Это то же самое, что и
eqv?
.eqv?
проверяет два объекта, чтобы определить, "обычно ли они рассматриваются как один и тот же объект".eqv?
иeq?
являются очень похожими операциями, и различия между ними будут зависеть от конкретной реализации.eq?
то же самое,eqv?
но может различать более тонкие различия и может быть реализован более эффективно.eqv?
.=
сравнивает числа на предмет численного равенства.(= 1 1.0 1/1 2/2)
источник
eq?
это фактическое равенство указателя (нетeqv?
). Это «самый лучший или самый разборчивый». Например(eqv? 2 2)
, гарантированно#t
, но(eq? 2 2)
"не указано". Т.е. это зависит от того, создает ли реализация фактический новый объект памяти для каждого вновь прочитанного числа или повторно использует ранее созданный объект, если это возможно.eq?
иeqv?
более тонкие, чем другие операции.Вы не упоминаете реализацию схемы, но в Racket
eq?
возвращает true , только если аргументы относятся к одному и тому же объекту. Второй пример дает #f, потому что система создает новое число с плавающей запятой для каждого аргумента; это не один и тот же объект.equal?
и=
проверяют эквивалентность значений, но=
применимо только к числам.Если вы используете Racket, проверьте здесь дополнительную информацию. В противном случае проверьте документацию по реализации вашей схемы.
источник
Думайте об этом
eq?
как о равенстве указателей. Авторы отчета хотят, чтобы он был как можно более общим, поэтому они не говорят об этом прямо, потому что это зависит от реализации, и, чтобы сказать, что это будет, предпочтительнее реализации на основе указателей. Но они говорятВот что я имею в виду.
(eqv? 2 2)
гарантированно вернется,#t
но(eq? 2 2)
не указан. Теперь представьте реализацию на основе указателя. В немeq?
просто сравнение указателей. Поскольку(eq? 2 2)
не указано, это означает, что эта реализация может просто создавать новое представление объекта памяти для каждого нового числа, которое он считывает из исходного кода.eqv?
должен действительно проверить его аргументы.OTOH
(eq 'a 'a)
есть#t
. Это означает, что такая реализация должна распознавать символы с повторяющимися именами и использовать один и тот же объект представления в памяти для всех из них.Предположим, что реализация не основана на указателях. Пока он придерживается Отчета, это не имеет значения. Авторы просто не хотят, чтобы их считали диктаторами конкретных реализаций разработчикам, поэтому они тщательно выбирают формулировки.
Во всяком случае, это мое предположение.
Итак, очень грубо,
eq?
равенство указателей,eqv?
(атомарные) значения,equal?
также известно структуру (проверяет свои аргументы рекурсивно, так что, наконец(equal? '(a) '(a))
, требуется#t
),=
для чисел,string=?
для строк, а детали в отчете.источник
Помимо предыдущих ответов, я добавлю несколько комментариев.
Все эти предикаты хотят определить абстрактную функцию
identity
объекта, но в разных контекстах.EQ?
зависит от реализации и не отвечает на вопросare 2 objects the same?
только при ограниченном использовании. С точки зрения реализации этот предикат просто сравнивает 2 числа (указатель на объекты), он не смотрит на содержимое объектов. Так, например, если ваша реализация не сохраняет строки внутри однозначно, а выделяет разную память для каждой строки, тогда(eq? "a" "a")
будет false.EQV?
- это заглядывает внутрь объектов, но с ограниченным использованием. Это зависит от реализации, если он возвращает true для(eqv? (lambda(x) x) (lambda(x) x))
. Здесь представлена полная философия того, как определять этот предикат, поскольку в настоящее время мы знаем, что есть несколько быстрых методов для сравнения функциональности некоторых функций с ограниченным использованием. Ноeqv?
дает последовательный ответ для больших чисел, строк и т. Д.На практике некоторые из этих предикатов пытаются использовать абстрактное определение объекта (математически), в то время как другие используют представление объекта (как это реализовано на реальной машине). Математическое определение идентичности исходит от Лейбница и гласит:
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.
В идеале это определение можно было бы реализовать на компьютере, но по причинам неопределенности и / или скорости оно не реализовано буквально. Вот почему существует множество операторов, которые пытаются сосредоточить внимание каждого на разных точках зрения на это определение.
Попробуйте представить себе абстрактное определение идентичности для продолжения. Даже если вы можете предоставить определение подмножества функций ( сигма-рекурсивный класс функций ), язык не требует, чтобы какой-либо предикат был истинным или ложным. Это сильно усложнило бы как определение языка, так и реализацию.
Контекст для других предикатов легче анализировать.
источник