Common Lisp-对象相等性 函数或谓词包括:eq、eql、equal、equalp、=

Common Lisp-对象相等性

函数或谓词包括:eq、eql、equal、equalp


在Lisp中,symbols(符号)是独一无二的,是指在计算机内存中,给定某个名字,只有一个symbol1。每一个symbol都有一个数值的位置,叫做地址。因为一个symbol只存在于内存中的一个位置,所以symbol有唯一的地址。所以在列表 (TIME AFTER TIME)中,出现两次的符号TIME一定是指向相同的地址的。不会有两个不同的symbol都叫TIME。

Common Lisp-对象相等性 函数或谓词包括:eq、eql、equal、equalp、=_第1张图片

另一方面,list(列表)不是唯一的。我们很容易就可以得到两个不同的列表 (A B C),只要分别创建两个cons cells链。两个list中的符号都是相同的,但是列表本身不是。这就意味着 EQUAL不能通过list的地址来比较list,因为(A B C)和(A B C)是相等的,即使它们有不同的cons cell链。因此EQUAL是通过一个个比较list中的元素来进行比较。如果list中相应的元素都相等,那么这些list被认为是相等的。

(setf x1 (list ‘a ‘b ‘c)) Make a fresh list (A B C).
(A B C)
(setf x2 (list ’a ’b ’c)) Make another list (A B C).
(A B C)
(equal x1 x2) The lists are EQUAL.
T

如果我们想去区分是否两个指针指向同一个对象,我们必须比较它们的地址。EQ谓词就是做这个的。Lists彼此是EQ的,只有当他们有相同的地址。

(eq x1 x2) The two lists are not EQ.
NIL
(setf z x1) Now Z points to the same list as X1.
(A B C)
(eq z x1) So Z and X1 are EQ.
T
(eq z ’(a b c)) These lists have different addresses.
NIL
(equal z ’(a b c)) But they have the same elements.
T

EQ函数比EQUAL快,因为EQ仅仅需要比较两个地址,而EQUAL需要首先判断输入是否为列表,如果是,它必须一一比较相应的元素。由于效率,当比较symbols时,程序员常用EQ替代EQUAL。但EQ不常用于list,除非是想确定两个cons cells链是否是一样的。
Numbers(数字)在Lisp系统中有不同的内部表示。在一些实现中,每个number有唯一的地址,而另一些实现不是这样。因此EQ绝不用来比较numbers。
EQL谓词是EQ稍微更通用点的一个变种。它像EQ一样比较两个对象(object)的地址,但是在对于相同类型(比如都是整数)的numbers时,它将按值来比较的。

(eql ’foo ’foo) => t
(eql 3 3) => t
(eql 3 3.0) => nil Different types.

在Lisp中,EQL是“标准”的比较函数。像 MEMBWE 和 ASSOC 这样内部包含相等性测试的函数就是用EQL的,除非显示设置为其他谓词。
在比较不同类型的numbers(数字)时,还有另一个相等性谓词叫 =。这个谓词是比较两个numbers时最高效的。任何其他种类的输入都会报错。

(= 3 3.0) => t
(= ’foo ’foo) => Error! FOO is not a number.

最后,EQUALP谓词和EQUAL相似,只是有一小些更自由。比如忽略字符串的大小写。

(equal “foo bar” “Foo BAR”) => nil
(equalp “foo bar” “Foo BAR”) => t

初学者经常对Common Lisp中这么多样的相等性测试感到迷惑。我建议忘掉所有的这些函数;只记住两条。第一,用EQUAL:它做你想要的。第二,记住那些内置的隐式含有相等性测试的函数,如 MEMBER和 ASSOC,由于效率原因默认是使用EQL。这就是说,这些函数在比较list时真确,除非告诉它们用别的相等性谓词。总结下:

  • EQ是最快的相等性测试:它比较的是地址。专家使用它对symbols(符号)快速地比较,测试两个cons cells是否物理上是同一个对象。不该用来比较numbers(数字)。
  • EQL和EQ类似,只是在比较同类型numbers时更安全,比如两个整数或两个浮点数。Common Lisp中,EQL是默认的相等性测试。
  • EQUAL 是初学者该用的谓词。他比较list(列表)时,是一个一个元素比较的;其他时候和EQL一样。
  • EQUALP 比EQUAL更宽松:比如它忽略字符串的大小写等。
  • =在比较numbers时是最高效的,也是唯一可用于比较不同类型的number的方法,比如 3 和 3.0 。它只接受number作为参数。

  1. 我们假设只有标准包的存在,并且没有 意外的符号(uninterned symbols.). ↩

你可能感兴趣的:(Lisp)