В чем разница между eq, eql, equal и equalp в Common Lisp? - PullRequest
69 голосов
/ 13 февраля 2009

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

Ответы [ 3 ]

75 голосов
/ 13 февраля 2009

С Обычный Лисп: Предикаты равенства

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

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

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

Два объекта equalp, если они равны; если они являются символами и удовлетворяют символу равно, что игнорирует буквенный регистр и некоторые другие атрибуты символов; если они являются числами и имеют одинаковое числовое значение, даже если они разных типов; или если они имеют все компоненты, которые 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.
28 голосов
/ 14 февраля 2009

Еще несколько заметок:

  • Большинство функций 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.

11 голосов
/ 15 февраля 2014

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

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

Например:

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

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

Например:

(eql 4 4.0) NIL
(eql 4 4) T

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

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

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

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

Например:

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

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

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

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

Например:

(равно (минусы 'а' б) (минусы 'а' б)) Т; такое же, как равно

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

равно (4,0) NIL
равно (4,0) Т; Как equp обрабатывает тип чисел нечувствительно

...