違いがよくわからなかったのでメモ。
6.2 等価 – Gauche ユーザリファレンス によると次のような違いがある。
eq?
最も高速で、細かい区別ができる述語。 2つの引数がアロケートされる同じ型のオブジェクトで、かつ両者がメモリ上の全く同じ場所を占めるオブジェクトを指している場合に #t を返す。2つの引数がともに文字、あるいは数値だった場合の振るまいは Scheme の標準では定められていない。
gosh> (eq? 'Foo 'Foo) #t gosh> (eq? "Foo" "Foo") #f gosh> (eq? #\a #\a) #t gosh> (eq? 123 123) #t gosh> (eq? '(Foo) '(Foo)) #f
Gauche の場合には文字列では #f になるけど、数値では #t になるな。
eqv?
2つの引数 obj1 と obj2 がともに正確な数値、あるいはともに(NaN以外の)不正確な数値である場合、(= obj1 obj2)が真であれば #t が、偽であれば #f が返される。obj1 と obj2 がともに文字である場合、(char=? obj1 obj2)が真であれば #t が、偽であれば #f が返される。それ以外の場合は、Gaucheでは eqv? は eq? と同じ。
gosh> (eqv? 'Foo 'Foo) #t gosh> (eqv? "Foo" "Foo") #f gosh> (eqv? #\a #\a) #t gosh> (eqv? 123 123) #t gosh> (eqv? '(Foo) '(Foo)) #f gosh>
eq? と同じじゃん。正確な数値とか不正確な数値とかがわかんないけど。
equal?
2つに引数 obj1 と obj2 がリストやベクタなどの複合型である場合、equal? は再帰的に対応する要素同士を equal? で比較する。そうでなければ equal? は eqv? と同じようにふるう。
gosh> (equal? 'Foo 'Foo) #t gosh> (equal? "Foo" "Foo") #t gosh> (equal? #\a #\a) #t gosh> (equal? 123 123) #t gosh> (equal? '(Foo) '(Foo)) #t
eq? や eqv? では #f になった文字列やリストでも #t になる。
まとめ
表にまとめると次のようになる。
オブジェクト | eq? | eqv? | equal? |
シンボル | #t | #t | #t |
文字列 | #f | #f | #t |
文字 | #t | #t | #t |
数値 | #t | #t | #t |
リスト | #f | #f | #t |
比べるのがシンボルの場合には eq?、文字の場合には eqv?、数値の場合には(上には出てこないけど)=、それ以外は equal? がいいみたいだ。
(eqv? 1.0 1.0)は常に#tですが、(eq? 1.0 1.0)は#fになることもあります。一般には、eqv? (同一性) と equal? (等価性) のみ覚えてれば良いと思います。
(eqv? 1.0 1) は#fですが、(= 1.0 1) は #t です。eqv?はオブジェクトのアイデンティティの同一性、=は数値としての同値性を判断します。