与 EQUAL EQUALP TREE-EQUAL 的结构相等

这三个运算符实现了结构等价,即它们检查不同的复杂对象是否具有等效组件的等效结构。

EQUAL 对于非结构化数据表现得像 EQL,而对于由 conses(列表和树)构建的结构,以及两种特殊类型的数组,字符串和位向量,它执行结构等价,在两个同构的结构上返回 true EQUAL 对应的基本成分相等。例如:

(equal (list 1 (cons 2 3)) (list 1 (cons 2 (+ 2 1))))
T ;; => since the two arguments are both equal to (1 (2 . 3))
(equal "ABC" "ABC")
T ;; => equality on strings
(equal "Abc" "ABC")
NIL ;; => case sensitive equality on strings
(equal '(1 . "ABC") '(1 . "ABC"))
T ;; => equal since it uses EQL on 1 and 1, and EQUAL on "ABC" and "ABC"
(let* ((a (make-array 3 :initial-contents '(1 2 3)))
       (b (make-array 3 :initial-contents '(1 2 3)))
       (c a))
  (values (equal a b)
          (equal a c)))
NIL ;; => the structural equivalence is not used for general arrays
T   ;; => a and c are alias for the same object, so it is like EQL

EQUALPEQUAL 为真的所有情况下都返回 true,但对于结构和哈希表(但不是类实例!),它对任何类型和维度的数组也使用结构等价。此外,它对字符串使用不区分大小写的等价。

(equalp "Abc" "ABC")
T ;; => case insensitive equality on strings
(equalp (make-array 3 :initial-contents '(1 2 3))
        (make-array 3 :initial-contents (list 1 2 (+ 2 1))))
T ;; => the structural equivalence is used also for any kind of arrays
(let ((hash1 (make-hash-table))
      (hash2 (make-hash-table)))
      (setf (gethash 'key hash1) 42)
      (setf (gethash 'key hash2) 42)
      (print (equalp hash1 hash2))
      (setf (gethash 'another-key hash1) 84)
      (equalp hash1 hash2))   
T   ;; => after the first two insertions, hash1 and hash2 have the same keys and values
NIL ;; => after the third insertion, hash1 and hash2 have different keys and values
(progn (defstruct s) (equalp (make-s) (make-s)))
T ;; => the two values are structurally equal
(progn (defclass c () ()) (equalp (make-instance 'c) (make-instance 'c)))
NIL ;; => two structurally equivalent class instances returns NIL, it's up to the user to
    ;;    define an equality method for classes

最后,TREE-EQUAL 可以应用于通过 cons 构建的结构,并检查它们是否是同构的,如 EQUAL,但是留给用户选择用于比较叶子的函数,即遇到的非缺点(原子),可以是任何其他数据类型(默认情况下,在 atom 上使用的测试是 EQL)。例如:

(let ((l1 '(1 . ("A" . 2)))
      (l2 '(1 . ("A" . 2))))
  (tree-equal l1 l2 :test #'eql))
NIL ;; => since (eql "A" "A") gives NIL
(let ((l1 '(1 . ("A" . 2)))
      (l2 '(1 . ("A" . 2))))
  (tree-equal l1 l2 :test #'equal))
T ;; since (equal "A" "A") gives T