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