符号相等

Symbol equality

Paul Graham's book ANSI Common Lisp 中,在讨论符号与字符串操作时,他说

Symbols can be compared in one step with eql ..."

(p138)。下面是符号比较的两种情况:

(setq x 3)
3
(setq a 'x)
X
(setq b 'x)
X
(eq a b)
T

因此,由于 ab 指向同一个符号对象,名为 "X",因此它们是 eq。然而,这与

(setq a (copy-symbol 'x))
#:X
(setq b (copy-symbol 'x))
#:X
(symbol-name a)
"X"
(symbol-name b)
"X"
(eq a b)
NIL
(eql a b)
NIL
(equal a b)
NIL
(equalp a b)
NIL

现在,ab 指向不同的 symbol 对象,即使它们具有相同的 symbol-name 和相同的打印名称。我的问题是:

  1. 为什么格雷厄姆说 eql 而不是 eq,并且
  2. 第二种情况,为什么ab不是至少equalp

eql over eq?

eql 是 "more predictable",因为它小于 implementation-dependent。 例如,non-immediate 个数字(即 非fixnums) can be non-eq 在某些实现中,在其他实现中 eq

(= 1.5d0 1.5d0)
=> T
(eql 1.5d0 1.5d0)
=> T
(eq 1.5d0 1.5d0)
=> T in some implementations, NIL in others

为什么同名符号不是 equalp

规范就是这么说的:-)

请注意,它确实违反了经验法则:

A rough rule of thumb is that two objects are equal if and only if their printed representations are the same.

主要的非histerical reason是那个符号,同时 "atomic",仍然背负着很多包袱(例如,变量和函数 绑定)。 IOW,symbol 是 远不止它的名字。

此外,人们通常期望 equal 表单的计算结果为 equal 值,如果不同的符号(带有 可能不同的绑定!)被评估为 equal.

现在,equalequalp 之间的唯一区别是

  1. case-insensitive 字符(和字符串)比较
  2. 使用 =
  3. 比较数字
  4. 递归下降到 structure, array, 和 hash-table.

None 这些变化会影响上面的 "similar evaluation rule", 所以 equalp 没有理由根据 他们的名字。

如果你想通过名称比较符号,你可以 使用 string=:

(eq '#:a '#:a)
==> NIL
(equalp '#:a '#:a)
==> NIL
(string= '#:a '#:a)
==> T