Какая разница между eq, eql, equal и equalp в Common Lisp?

В чем разница между eq, eql, equal и equalp, в Common Lisp? Я понимаю, что некоторые из них проверяют типы, некоторые из них проверяют все типы, но что это такое? Когда лучше использовать, чем другие?

Ответ 1

От Common Lisp: Предикаты равенства

(eq xy) истинно тогда и только тогда, когда x и y - один и тот же идентичный объект.

Предикат eql истинен, если его аргументы равны eq, или если они являются номерами одного и того же типа с одинаковым значением или являются символьными объектами, которые представляют один и тот же символ.

equal предикат является истинным, если его аргументы являются структурно подобными (изоморфными) объектами. Грубое эмпирическое правило состоит в том, что два объекта равны тогда и только тогда, когда их печатные представления одинаковы.

Два объекта равны equalp если они равны; если они являются символами и удовлетворяют char-equal, что игнорирует алфавитный случай и некоторые другие атрибуты символов; если они являются числами и имеют одинаковое числовое значение, даже если они имеют разные типы; или если у них есть компоненты, все equalp.

Вот несколько примеров из той же страницы, с которой я связан выше:

(eq 'a 'b) is false. 
(eq 'a 'a) is true. 
(eq 3 3) might be true or false, depending on the implementation. 
(eq 3 3.0) is false. 
(eq 3.0 3.0) might be true or false, depending on the implementation. 
(eq #c(3 -4) #c(3 -4)) 
  might be true or false, depending on the implementation. 
(eq #c(3 -4.0) #c(3 -4)) is false. 
(eq (cons 'a 'b) (cons 'a 'c)) is false. 
(eq (cons 'a 'b) (cons 'a 'b)) is false. 
(eq '(a . b) '(a . b)) might be true or false. 
(progn (setq x (cons 'a 'b)) (eq x x)) is true. 
(progn (setq x '(a . b)) (eq x x)) is true. 
(eq #\A #\A) might be true or false, depending on the implementation. 
(eq "Foo" "Foo") might be true or false. 
(eq "Foo" (copy-seq "Foo")) is false. 
(eq "FOO" "foo") is false.


(eql 'a 'b) is false. 
(eql 'a 'a) is true. 
(eql 3 3) is true. 
(eql 3 3.0) is false. 
(eql 3.0 3.0) is true. 
(eql #c(3 -4) #c(3 -4)) is true. 
(eql #c(3 -4.0) #c(3 -4)) is false. 
(eql (cons 'a 'b) (cons 'a 'c)) is false. 
(eql (cons 'a 'b) (cons 'a 'b)) is false. 
(eql '(a . b) '(a . b)) might be true or false. 
(progn (setq x (cons 'a 'b)) (eql x x)) is true. 
(progn (setq x '(a . b)) (eql x x)) is true. 
(eql #\A #\A) is true. 
(eql "Foo" "Foo") might be true or false. 
(eql "Foo" (copy-seq "Foo")) is false. 
(eql "FOO" "foo") is false.


(equal 'a 'b) is false. 
(equal 'a 'a) is true. 
(equal 3 3) is true. 
(equal 3 3.0) is false. 
(equal 3.0 3.0) is true. 
(equal #c(3 -4) #c(3 -4)) is true. 
(equal #c(3 -4.0) #c(3 -4)) is false. 
(equal (cons 'a 'b) (cons 'a 'c)) is false. 
(equal (cons 'a 'b) (cons 'a 'b)) is true. 
(equal '(a . b) '(a . b)) is true. 
(progn (setq x (cons 'a 'b)) (equal x x)) is true. 
(progn (setq x '(a . b)) (equal x x)) is true. 
(equal #\A #\A) is true. 
(equal "Foo" "Foo") is true. 
(equal "Foo" (copy-seq "Foo")) is true. 
(equal "FOO" "foo") is false.


(equalp 'a 'b) is false. 
(equalp 'a 'a) is true. 
(equalp 3 3) is true. 
(equalp 3 3.0) is true. 
(equalp 3.0 3.0) is true. 
(equalp #c(3 -4) #c(3 -4)) is true. 
(equalp #c(3 -4.0) #c(3 -4)) is true. 
(equalp (cons 'a 'b) (cons 'a 'c)) is false. 
(equalp (cons 'a 'b) (cons 'a 'b)) is true. 
(equalp '(a . b) '(a . b)) is true. 
(progn (setq x (cons 'a 'b)) (equalp x x)) is true. 
(progn (setq x '(a . b)) (equalp x x)) is true. 
(equalp #\A #\A) is true. 
(equalp "Foo" "Foo") is true. 
(equalp "Foo" (copy-seq "Foo")) is true. 
(equalp "FOO" "foo") is true.

Ответ 2

Некоторые примечания:

  • Большинство функций CL неявно используют EQL, если не указан тест

  • См. также STRING-EQUAL, = и TREE-EQUAL

  • В основе EQ обычно входит сравнение указателей

И приблизительное руководство:

To compare against...      Use...

Objects/Structs            EQ

NIL                        EQ (but the function NULL is more concise and probably cheaper)

T                          EQ (or just the value but then you don't care for the type)

Precise numbers            EQL

Floats                     =

Characters                 EQL or CHAR-EQUAL

Lists, Conses, Sequences   EQ (if you want the exact same object)
                           EQUAL (if you just care about elements)

Strings                    EQUAL (case-sensitive), EQUALP (case-insensitive)
                           STRING-EQUAL (if you throw symbols into the mix)

Trees (lists of lists)     TREE-EQUAL (with appropriate :TEST argument)

Обратите внимание, что для эффективности обычно EQ → EQL → EQUAL → EQUALP.

Ответ 3

Из здесь и мои слайды учителя

eq, чтобы проверить, являются ли его аргументы (представленные одним и тем же блоком памяти компьютера) одним и тем же символом.

Пример:

(eq 'A' B) NIL
(эквалайзер ОЗУ RAM) T
(eq (cons 'a' b) (cons a 'b')); Это связано с тем, что для обоих минусов выполняются разные вызовы, поэтому им, очевидно, будут выделены разные фрагменты памяти.

eql первые тесты, чтобы убедиться, что его аргументы удовлетворяют EQ, если нет, он пытается увидеть, если они являются номерами одного типа и значений.

Пример:

(eql 4,04) NIL
(eql 4 4) T

Теперь обратите внимание на разницу:

(eq 4.0 4.0) NIL; Зависит от платформы, как описано в первом (принятом) ответе
(eql 4.0 4.0) T; тип и значение аргументов одинаковы

В некоторых реализациях (eq 4.0 4.0) может возвращаться true, потому что в стандарте не указано, должна ли реализация содержать только одну копию чисел и символов в памяти, как это происходит с символами). Как правило, правило не использовать eq для чисел и символов, если вы действительно не знаете, что делаете.

equal - это "более простая" функция сравнения. Как правило, вы можете думать об этом как о том, являются ли два объекта одинаковыми (структурно схожими или изоморфными). Вероятно, это оператор, который вы хотите использовать для общего равенства. Он ведет себя как eql для чисел, символов и символов, но для списков (conses) и строк он сообщает, если их элементы

Пример:

(равный 4 4) T
(равно (+ 2 2) 4) T

Теперь обратите внимание на разницу

(eql (cons 'a' b) (cons 'a' b)) NIL
(равный (минус "a" b) (cons "a" b)) T; равное обычно справедливо для вещей, которые печатают тот же

equalp как равный, просто более продвинутый. Сравнение чисел нечувствительно к типу. Сравнение символов и строк нечувствительно к регистру.

Пример:

(equalp (cons 'a' b) (cons 'a' b)) T, то же самое, что и

Теперь обратите внимание на разницу

равно (4,0) NIL
equalp (4,0,0) T; Поскольку equalp относится к типу чисел нечувствительно