web-dev-qa-db-ja.com

Common Lispのeq、eql、equal、equalpの違いは何ですか?

Common Lispのeqeqlequalequalpの違いは何ですか?それらのいくつかは型をチェックし、いくつかは型全体をチェックすることを理解していますが、どれがどれですか?いつ他のものよりも使用する方が良いですか?

69
Cristián Romo

From Common LISP:Equality Predicates

(eq x y)は、xyが同じ同一オブジェクトである場合にのみ真です。

eql述部は、引数がeqである場合、同じ値を持つ同じタイプの数値である場合、または同じ文字を表す文字オブジェクトである場合に真になります。

equal述語は、その引数が構造的に類似した(同形の)オブジェクトである場合に真になります。大まかな経験則では、2つのオブジェクトは、印刷された表現が同じ場合にのみ等しいということです。

2つのオブジェクトは、等しい場合はequalpです。それらが文字であり、char-equalを満たしている場合、アルファベットの大文字と文字の特定の他の属性を無視します。それらが数値であり、それらが異なるタイプであっても同じ数値を持っている場合;または、すべてequalpであるコンポーネントがある場合。

上記にリンクした同じページの例をいくつか示します。

(eq 'a 'b) is false. 
(eq 'a 'a) is true. 
(eq 3 3) might be true or false, depending on the implementation. 
(eq 3 3.0) is false. 
(eq 3.0 3.0) might be true or false, depending on the implementation. 
(eq #c(3 -4) #c(3 -4)) 
  might be true or false, depending on the implementation. 
(eq #c(3 -4.0) #c(3 -4)) is false. 
(eq (cons 'a 'b) (cons 'a 'c)) is false. 
(eq (cons 'a 'b) (cons 'a 'b)) is false. 
(eq '(a . b) '(a . b)) might be true or false. 
(progn (setq x (cons 'a 'b)) (eq x x)) is true. 
(progn (setq x '(a . b)) (eq x x)) is true. 
(eq #\A #\A) might be true or false, depending on the implementation. 
(eq "Foo" "Foo") might be true or false. 
(eq "Foo" (copy-seq "Foo")) is false. 
(eq "FOO" "foo") is false.


(eql 'a 'b) is false. 
(eql 'a 'a) is true. 
(eql 3 3) is true. 
(eql 3 3.0) is false. 
(eql 3.0 3.0) is true. 
(eql #c(3 -4) #c(3 -4)) is true. 
(eql #c(3 -4.0) #c(3 -4)) is false. 
(eql (cons 'a 'b) (cons 'a 'c)) is false. 
(eql (cons 'a 'b) (cons 'a 'b)) is false. 
(eql '(a . b) '(a . b)) might be true or false. 
(progn (setq x (cons 'a 'b)) (eql x x)) is true. 
(progn (setq x '(a . b)) (eql x x)) is true. 
(eql #\A #\A) is true. 
(eql "Foo" "Foo") might be true or false. 
(eql "Foo" (copy-seq "Foo")) is false. 
(eql "FOO" "foo") is false.


(equal 'a 'b) is false. 
(equal 'a 'a) is true. 
(equal 3 3) is true. 
(equal 3 3.0) is false. 
(equal 3.0 3.0) is true. 
(equal #c(3 -4) #c(3 -4)) is true. 
(equal #c(3 -4.0) #c(3 -4)) is false. 
(equal (cons 'a 'b) (cons 'a 'c)) is false. 
(equal (cons 'a 'b) (cons 'a 'b)) is true. 
(equal '(a . b) '(a . b)) is true. 
(progn (setq x (cons 'a 'b)) (equal x x)) is true. 
(progn (setq x '(a . b)) (equal x x)) is true. 
(equal #\A #\A) is true. 
(equal "Foo" "Foo") is true. 
(equal "Foo" (copy-seq "Foo")) is true. 
(equal "FOO" "foo") is false.


(equalp 'a 'b) is false. 
(equalp 'a 'a) is true. 
(equalp 3 3) is true. 
(equalp 3 3.0) is true. 
(equalp 3.0 3.0) is true. 
(equalp #c(3 -4) #c(3 -4)) is true. 
(equalp #c(3 -4.0) #c(3 -4)) is true. 
(equalp (cons 'a 'b) (cons 'a 'c)) is false. 
(equalp (cons 'a 'b) (cons 'a 'b)) is true. 
(equalp '(a . b) '(a . b)) is true. 
(progn (setq x (cons 'a 'b)) (equalp x x)) is true. 
(progn (setq x '(a . b)) (equalp x x)) is true. 
(equalp #\A #\A) is true. 
(equalp "Foo" "Foo") is true. 
(equalp "Foo" (copy-seq "Foo")) is true. 
(equalp "FOO" "foo") is true.
76
Bill the Lizard

いくつかのメモ:

  • テストが指定されていない場合、ほとんどのCL関数は暗黙的にEQLを使用します

  • STRING-EQUAL、=およびTREE-EQUALも参照してください

  • EQの中核は通常、ポインター比較です

大まかなガイド:

と比較するには...使用... 
 
 Objects/Structs EQ 
 
 NIL EQ(ただし、NULL関数はより簡潔で、おそらく安い)
 
 T EQ(または単に値ですが、タイプは気にしません)
 
正確な数値EQL 
 
 Floats = 
 
 Characters EQLまたはCHAR-EQUAL 
 
 Lists、Conses、Sequences EQ(正確に同じオブジェクトが必要な場合)
 EQUAL(要素だけに関心がある場合)
 
 Strings EQUAL(大文字と小文字を区別する)、EQUALP(大文字と小文字を区別しない)
 STRING-EQUAL(シンボルをスローする場合mix)
 
ツリー(リストのリスト)TREE-EQUAL(適切な:TEST引数付き)

通常、効率のためにEQ >> EQL >> EQUAL >> EQUALPに注意してください。

28

こちら と私の先生のスライドから

eqは、その引数(同じコンピューターメモリのチャンクで表される)が同じシンボルであるかどうかをテストします。

例えば:

(eq ‘A’ B)NIL
(eq´RAM´RAM)T
(eq(cons 'a' b)(cons a 'b')); これは、両方の短所に対して異なる呼び出しが行われ、明らかに異なるメモリチャンクが割り当てられるためです

eql最初に、引数がEQを満たしているかどうかを確認し、そうでない場合は、同じタイプと値の数値であるかどうかを確認します。

例えば:

(eql 4 4.0)NIL
(eql 4 4)T

ここで、differenceに注意してください:

(eq 4.0 4.0)NIL;最初の(受け入れられた)回答で説明されているようにプラットフォームに依存
(eql 4.0 4.0)T;引数のタイプと値は同じです

一部の実装(eq 4.0 4.0)では、実装がシンボルの場合のようにメモリ内に数字と文字のコピーを1つだけ保持するかどうかが規格で指定されていないため、trueを返す場合があります)。経験則数字と文字にeqを使用しないあなたが本当に何を知っているのでない限りやり直します。

equalは「saner」比較関数です。経験則として、2つのオブジェクトが同じように見える(構造的に似ている、または同形)かどうかを伝えると考えることができます。これはおそらく、一般的な平等のために使用する演算子です。数字、文字、記号についてはeqlのように動作しますが、リスト(cons)および文字列については、それらの要素が

例えば:

(等しい4 4)T
(等しい(+ 2 2)4)T

differenceに注意してください

(eql(cons 'a' b)(cons 'a' b))NIL
(等しい(cons 'a' b)(cons 'a' b))T; equalは通常、同じものを印刷するものに当てはまります

equalpはequalと似ており、より高度です。数値の比較では型は区別されません。文字と文字列の比較では、大文字と小文字は区別されません。

例えば:

(equalp(cons 'a' b)(cons 'a' b))T;equalと同じ

differenceに注意してください

等しい(4 4.0)NIL
equalp(4 4.0)T; equalpが数値を区別せずに扱うため

11
A.s. Bhullar