수색…


EQ와 EQL의 차이점

  1. EQ 는 두 값의 메모리 주소가 같은지 확인합니다. 즉 두 값이 실제로 동일 하고 동일한 개체인지 확인합니다. 그래서, 그것은 신원 검사로 간주 될 수 있으며, 단지 구조물에 적용되어야합니다 : cons, 배열, 구조체, 객체, 일반적으로 당신이 실제로 동일한 객체가 다른 경로를 통해 도달했는지, 다른 변수들.

  2. EQL 은 두 개의 구조체가 같은 객체인지 ( EQ 와 같은) 또는 구조화되지 않은 동일한 값 (즉, 같은 유형 또는 문자 값의 숫자에 대해 동일한 숫자 값)인지 여부를 확인합니다. 이것은 EQ 연산자를 포함하고 구조화되지 않은 값에도 사용할 수 있으므로 가장 중요하고 가장 많이 사용되는 연산자이며 MEMBER 와 같은 등가 비교가 필요한 거의 모든 기본 함수는 기본적으로이 연산자를 사용 합니다.

따라서, (EQ XY) (EQL XY) 의미하는 반면, 그 반대는 유지되지 않습니다.

몇 가지 예를 통해 두 연산자의 차이를 정리할 수 있습니다.

(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 사용에 반대하는 이유를 알 수 있습니다.

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 인 모든 경우에 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 하지만, (원자)가 발생 비 단점 즉, 잎을 비교하기 위해 사용하는 기능을 선택할 수있는 사용자에게 떠나, 다른 모든 데이터 유형이 될 수 있습니다 (기본적으로 원자에 사용 된 테스트는 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

숫자 값 비교 연산자

숫자 값은 = 및 다른 숫자 유형의 실제 표현의 차이를 무시하는 다른 숫자 비교 연산자 ( /= , < , <= , > , >= )와 비교할 수 있으며 해당 수학 값의 비교를 수행 할 수 있습니다 . 예를 들면 :

(= 42 42)
T ;; => both number have the sme numeric type and the same value
(= 1 1.0 1d0)
T ;; => all the tree values represent the number 1, while for instance (eql 1 1d0) => NIL
  ;;    since it returns true only if the operands have the same numeric type
(= 0.0 -0.0)
T ;; => again, the value is the same, while (eql 0.0 -0.0) => NIL
(= 3.0 #c(3.0 0.0))
T ;; => a complex number with 0 imaginary part is equal to a real number
(= 0.33333333 11184811/33554432)
T ;; => since a float number is passed to RATIONAL before comparing it to another number
  ;; => and (RATIONAL 0.33333333) => 11184811/33554432 in 32-bit IEEE floats architectures
(= 0.33333333 0.33333334)
T ;; => since the result of RATIONAL on both numbers is equal in 32-bit IEEE floats architectures
(= 0.33333333d0 0.33333334d0)
NIL ;; => since the RATIONAL of the two numbers in double precision is different

이 예제에서 우리는 두 개의 숫자 값이 같은 숫자 유형을 가지고있는 경우 에만 동일하다는 사실을 엄격히 밝히지 않는 한, = 는 숫자 값 사이의 비교를 수행하는 데 일반적으로 사용되는 연산자라고 결론 지을 수 있습니다. 어떤 경우에는 EQL 이 사용되어야한다.

문자 및 문자열 비교 연산자

Common Lisp에는 2 개의 문자를 비교하기위한 12 개의 유형별 연산자가 있으며 그 중 6 개는 대소 문자를 구분하고 나머지는 대소 문자를 구분합니다. 그들의 이름은 그 의미를 쉽게 기억할 수있는 간단한 패턴을 가지고 있습니다 :

대소 문자 구분 대소 문자를 구분하지 않음
CHAR = 자모
CHAR / = CHAR-NOT-EQUAL
CHAR < CHAR-LESSP
CHAR <= CHAR-NOT-GREATERP
CHAR> CHAR-GREATERP
CHAR> = CHAR-NOT-LESSP

같은 케이스의 2 문자는, CHAR-CODE 의해 취득 된 대응하는 코드와 같은 순서로 a..z 됩니다. 대문자와 소문자를 구별하지 않는 경우, 2 개의 범위 a..z , A..Z 로부터 취해진 임의의 2 개의 문자의 상대 순서는 구현에 의존합니다 . 예 :

(char= #\a #\a)
T ;; => the operands are the same character
(char= #\a #\A)
NIL ;; => case sensitive equality
(CHAR-EQUAL #\a #\A)
T ;; => case insensitive equality
(char> #\b #\a)
T ;; => since in all encodings (CHAR-CODE #\b) is always greater than (CHAR-CODE #\a)
(char-greaterp #\b \#A)
T ;; => since for case insensitive the ordering is such that A=a, B=b, and so on,
  ;;    and furthermore either 9<A or Z<0.
(char> #\b #\A)
?? ;; => the result is implementation dependent

문자열의 경우 특정 연산자는 CHAR 대신 STRING= , STRING-EQUAL 등의 단어가 STRING입니다. 그들은 문자 수가 동일하고 correspending 자에있어서 동일한 경우 두 문자열은 동일하다 CHAR= 또는 CHAR-EQUAL 테스트 대소 문자인지 아닌지.

문자열 사이의 순서는 두 문자열의 문자에 대한 사전 순서입니다. 순서 비교가 성공하면 결과는 T 가 아니라 두 문자열이 다른 첫 번째 문자의 색인이됩니다 (NIL이 아닌 모든 객체는 Common Lisp에서 "일반화 된 부울"이므로 true와 같습니다).

중요한 것은 string에 대한 모든 비교 연산자가 start1 , end1 , start2 , end2 와 같은 네 개의 키워드 매개 변수를 허용한다는 것입니다.이 매개 변수는 비교를 하나 또는 두 개의 문자열 내부의 연속 된 문자만으로 제한하는 데 사용할 수 있습니다. 생략 된 경우 시작 인덱스는 0이고 끝 인덱스는 생략되며 문자열의 길이와 :start index :start 가있는 문자에서 :start 하여 인덱스 :end - 1 포함 된 문자로 끝나는 하위 문자열에서 비교를 수행합니다.

마지막으로, 한 문자로 된 문자열은 문자와 비교할 수 없습니다.

예 :

(string= "foo" "foo")
T ;; => both strings have the same lenght and the characters are `CHAR=` in order
(string= "Foo" "foo")
NIL ;; => case sensitive comparison
(string-equal "Foo" "foo")
T ;; => case insensitive comparison
(string= "foobar" "barfoo" :end1 3 :start2 3)
T ;; => the comparison is perform on substrings
(string< "fooarr" "foobar")
3 ;; => the first string is lexicographically less than the second one and 
  ;;   the first character different in the two string has index 3
(string< "foo" "foobar")
3 ;; => the first string is a prefix of the second and the result is its length

특수한 경우로 문자열 비교 연산자를 기호에도 적용 할 수 있으며 기호의 SYMBOL-NAME 에 대한 비교가 이루어집니다. 예를 들면 :

(string= 'a "A")
T ;; since (SYMBOL-NAME 'a) is "A"
(string-equal '|a| 'a)
T ;; since the the symbol names are "a" and "A" respectively

마지막으로, 문자에 대한 EQLCHAR= 과 같습니다. 문자열의 EQUALSTRING= 과 같지만 문자열의 EQUALPSTRING-EQUAL 과 같습니다.

간과하다

Common Lisp에는 값을 비교하기위한 많은 다른 술어가 있습니다. 다음 범주로 분류 할 수 있습니다.

  1. 일반 평등 연산자 : EQ, EQL, EQUAL, EQUALP. 모든 유형의 값에 사용할 수 있으며 항상 부울 값 T 또는 NIL을 리턴합니다.
  2. 숫자에 대해서는 = 및 =을, 문자에 대해서는 CHAR = CHAR = CHAR-EQUAL CHAR-NOT-EQUAL, 문자열에 대해서는 STRING = STRING-EQUAL STRING-NOT-EQUAL, conses에 대해서는 TREE-EQUAL을 입력하십시오.
  3. 숫자 값의 비교 연산자 : <, <=,>,> =. 그들은 모든 유형의 숫자에 적용 할 수 있으며 실제 유형과 독립적으로 숫자의 수학적 가치를 비교할 수 있습니다.
  4. CHAR <, CHAR-LESSP 등과 같이 대소 문자를 구분하거나 대소 문자를 구분하지 않고 문자를 비교하는 자연어 사전 순을 유지하는 구현 방식에 따라 문자를 비교하는 연산자입니다.
  5. 문자 비교 연산자를 사용하여 문자열을 사전 식으로 비교하는 대소 문자를 구분하거나 대소 문자를 구분하지 않는 STRING, STRING-LESSP 등과 같은 문자열에 대한 비교 연산자입니다.


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow