eq? eqv? equal? の使い分け

同値かどうかの判定に q? eqv? equal? のうちどれを使えば良いか分からなかったのでGauche ユーザリファレンス 6.1 等価を参考にテストしてみた。

(define (list-for-each pred dat ls)
  (call/cc
    (lambda (return)
      (for-each 
        (lambda (x) (if (pred x dat) (return x)))
        ls)
      "not found")))

(define test '((abc)(1 2 ("def")) "hello" 999 hijk 0.123))

(define dat1 (car (cdr test)))  ; メモリ上の同じオブジェクト
(define dat2 'hijk)
(define dat3 999)
(define dat4 0.123)
(define dat5 "hello")
(define dat6 '(1 2 ("def")))

(print (list-for-each eq? dat1 test))        ;=> (1 2 (def))
(print (list-for-each eq? dat2 test))        ;=> hijk
(print (list-for-each eq? dat3 test))        ;=> 999
(print (list-for-each eq? dat4 test))        ;=> not found
(print (list-for-each eq? dat5 test))        ;=> not found
(print (list-for-each eq? dat6 test))        ;=> not found

(print (list-for-each eqv? dat1 test))       ;=> (1 2 (def))
(print (list-for-each eqv? dat2 test))       ;=> hijk
(print (list-for-each eqv? dat3 test))       ;=> 999
(print (list-for-each eqv? dat4 test))       ;=> 0.123
(print (list-for-each eqv? dat5 test))       ;=> not found
(print (list-for-each eqv? dat6 test))       ;=> not found

(print (list-for-each equal? dat1 test))     ;=> (1 2 (def))
(print (list-for-each equal? dat2 test))     ;=> hijk
(print (list-for-each equal? dat3 test))     ;=> 999
(print (list-for-each equal? dat4 test))     ;=> 0.123
(print (list-for-each equal? dat5 test))     ;=> hello
(print (list-for-each equal? dat6 test))     ;=> (1 2 (def))

eq? eqv? equal? の使い分けについて検索すると「Schemeへの道/述語」があった。

eq?,eqv?,equal?では,等しいと判定される判断基準が異なる.

 * eq?は,比較する2つの引数がシステム内部で同一のデータ(セル)を指し示している場合に#tを返す.
 * eqv?は,eq?で等しいか数値として等しい2つの引数が与えられたとき#tを返す.
 * equal?は,評価した結果が等しいような2つの引数が与えられたとき#tを返す.
 * eq?で等しいと判定されるデータは,eqv?,equal?でも等しい.
 * eqv?で等しいと判定されるデータは,equal?でも等しい.
 * equal?で等しいと判定されるデータがeqv?,eq?で等しいとは限らない.
 * eqv?で等しいと判定されるデータがeq?で等しいとは限らない.
 * equal?は汎用的.eq?は高速. 

直観的には,

 * symbolの比較には,eq?
 * symbolと数値を同時に扱う場合は,eqv?(数値のみを扱う場合は,"="の方がよい)
 * listの構造の比較には,equal? 

を使う.