Common Lisp中的eq,eql,equal和equalp有什么区别?

Common Lisp中的eqeqlequalequalp什么区别? 我明白,其中一些检查types,其中一些跨所有types检查,但哪个是哪个? 什么时候比别人更好用?

从共同的Lisp:平等预测

(eq xy)当且仅当xy是相同的同一个对象时才是真的。

如果eql谓词的参数是eq ,或者它们是具有相同值的相同types的数字,或者它们是表示相同字符的字符对象,则eql谓词为true。

如果它的参数是结构相似的(同构的)对象,那么equal谓词是真的。 一个粗略的经验法则是两个对象是相等的,当且仅当它们的打印表示是相同的。

两个对象是equalp如果他们是平等的; 如果它们是字符并且满足char-equal,忽略字母大小写和字符的某些其他属性; 如果它们是数字并且具有相同的数值,即使它们是不同的types; 或者如果他们的组件都是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 xx)) is true. (progn (setq x '(a . b)) (eq xx)) 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 xx)) is true. (progn (setq x '(a . b)) (eql xx)) 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 xx)) is true. (progn (setq x '(a . b)) (equal xx)) 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 xx)) is true. (progn (setq x '(a . b)) (equalp xx)) is true. (equalp #\A #\A) is true. (equalp "Foo" "Foo") is true. (equalp "Foo" (copy-seq "Foo")) is true. (equalp "FOO" "foo") is true. 

更多的注意事项:

  • 当没有指定testing时,大多数CL函数隐含地使用EQL

  • 另见STRING-EQUAL,=和TREE-EQUAL

  • EQ的核心通常是一个指针比较

和一个粗略的指导:

比较...使用...

对象/结构EQ

 NIL EQ(但函数NULL更简洁,可能更便宜)

 T EQ(或只是价值,但你不关心的types)

精确的数字EQL

浮动=

字符EQL或CHAR-EQUAL

列表,Conses,序列EQ(如果你想要完全相同的对象)
                           平等(如果你只关心元素)

stringEQUAL(区分大小写),EQUALP(区分大小写)
                            STRING-EQUAL(如果您将符号投入混合)

树(列表清单)TREE-EQUAL(具有适当的:TEST参数)

请注意,对于效率通常EQ >> EQL >> EQUAL >> EQUALP。

从这里和我的老师的幻灯片

eqtesting以查看它的参数(由相同的计算机内存块表示)是否是相同的符号。

例如:

(eq'A'B)NIL
(eq'RAM'RAM)T
(eq(cons'a'b)(cons a'b')); 这是因为不同的调用是为了这两个缺点,所以他们显然会被分配不同的内存块

eql首先testing它的参数是否满足EQ,如果不是,它会尝试查看它们是否是相同types和值的数字。

例如:

(eql 4 4.0)无
(eql 4 4)T

现在注意一下区别

(方程4.0 4.0)无;依据第一个(接受的)答案中所描述的平台
(eql 4.0 4.0)T;参数的types和值是相同的

在某些实现(例如4.0 4.0)上可能会返回true,因为在标准中没有指定实现是否应该在内存中只保留一个数字和字符的副本,就像使用符号一样)。根据经验 ,不要使用eq数字和字符除非你真的知道你在做什么。

平等是一个“更加健全”的比较function。 作为一个经验法则,你可以把它看作是告诉你两个物体看起来是否相同(结构相似或同构)。 这可能是您希望用于普遍平等的运营商。 它的行为就像eql中的数字,字符和符号,但是对于列表(conses)和string,它会告诉它们是否是它们的元素

例如:

(等于4 4)T
(等于(+ 2 2)4)T

现在注意一个区别

(eql(缺'a'b)(缺'a'b))无
(相等(cons'a'b)(cons'a'b))T; 对于打印相同的东西通常是相同的

equalp就像平等,只是更先进。 数字的比较是types不敏感的。 字符和string的比较是不区分大小写的。

例如:

(cons'a'b)(cons'a'b))T; 相同

现在注意一个区别

相等(4 4.0)无
equalp(4 4.0)T; 由于equalp对待数字types不敏感