EQ 和 EQL 之间的区别

  1. EQ 检查两个值是否具有相同的内存地址:换句话说,它检查这两个值是否实际上是相同的相同的对象。因此,它可以被认为是身份测试,并且应该应用于结构:conses,数组,结构,对象,通常用于查看你是否正在处理通过不同路径到达的相同对象,或者通过别名来处理不同的变量。

  2. EQL 检查两个结构是否是同一个对象(如 EQ),或者它们是否是相同的非结构化值(即相同类型的数字或字符值的相同数值)。由于它包含 EQ 运算符并且也可以用于非结构化值,因此是最重要和最常用的运算符,几乎所有需要相等比较的原始函数(如 MEMBER默认使用此运算符

因此,(EQ X Y) 总是意味着 (EQL X Y),而反之亦然。

一些例子可以清除两个运算符之间的差异:

(eq 'a 'a)
T ;; => since two s-expressions (QUOTE A) are `internalized` as the same symbol by the reader.
(eq (list 'a) (list 'a))
NIL ;; => here two lists are generated as different objects in memory
(let* ((l1 (list 'a))
       (l2 l1))
  (eq l1 l2))
T ;; => here there is only one list which is accessed through two different variables
(eq 1 1)
?? ;; it depends on the implementation: it could be either T or NIL if integers are `boxed`
(eq #\a #\a)
?? ;; it depends on the implementation, like for numbers
(eq 2d0 2d0)
?? ;; => dependes on the implementation, but usually is NIL, since numbers in double 
   ;;    precision are treated as structures in many implementations
(let ((a1 2d0)
      (a2 2d0))
  (eq a1 a2))
?? ;; => also in this case the results depends on the implementation

让我们用 EQL 尝试相同的例子:

(eql 'a 'a)
T ;; => equal because they are the same value, as for EQ
(eql (list 'a) (list 'a))
NIL ;; => different because they different objects in memory, as for EQ
(let* ((l1 (list 'a))
       (l2 l1))
  (eql l1 l2))
T ;; => as above
(eql 1 1)
T ;; they are the same number, even if integers are `boxed`
(eql #\a #\a)
T ;; they are the same character
(eql 2d0 2d0)
T ;; => they are the same number, even if numbers in double precision are treated as
   ;;   structures in many implementations
(let ((a1 2d0)
      (a2 2d0))
  (eql a1 a2))
T ;; => as before
(eql 2 2.0)
NIL;; => since the two values are of a different numeric type

从示例中我们可以看出为什么 EQL 运算符应该用于可移植地检查所有值的相同性,结构化和非结构化,以及为什么实际上许多专家建议不要使用 EQ