[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.1 等価

Schemeには等価性を判定する汎用的な述語が3つあります。 また、これらの他に、いくつかの型はその型同士で使える比較手続きを持っています。

Function: eq? obj1 obj2

[R5RS] 最も高速で、細かい区別ができる述語です。 obj1obj2がアロケートされる同じ型のオブジェクトで、 かつ両者がメモリ上の全く同じ場所を占めるオブジェクトを指している場合に #tを返します。また、obj1obj2がともに #f, #tあるいは()である場合も#tを返します。 ポインタ比較と考えても良いでしょう。 obj1obj2がともに文字、あるいは数値であった場合の振るまいは Schemeの標準では定められていません。

 
(eq? #t #t)               ⇒ #t
(eq? #t #f)               ⇒ #f
(eq? 'a 'a)               ⇒ #t
(eq? 'a 'b)               ⇒ #f
(eq? (list 'a) (list 'a)) ⇒ #f
(let ((x (list 'a)))
  (eq? x x))              ⇒ #t
Function: eqv? obj1 obj2

[R5RS] obj1obj2がともに正確な数値、もしくはともに不正確な数値である場合、 (= obj1 obj2)が真であれば#tが、偽であれば#fが 返されます。 obj1obj2がともに文字である場合、 (char=? obj1 obj2)が真であれば#tが、偽であれば#fが 返されます。 それ以外の場合は、Gaucheではeqv?eq?と同じです。

 
(eqv? #\a #\a)             ⇒ #t
(eqv? #\a #\b)             ⇒ #f
(eqv? 1.0 1.0)             ⇒ #t
(eqv? 1 1)                 ⇒ #t
(eqv? 1 1.0)               ⇒ #f
(eqv? (list 'a) (list 'a)) ⇒ #f
(let ((x (list 'a)))
  (eqv? x x))              ⇒ #t
Function: equal? obj1 obj2

[R5RS+] obj1obj2がリストやベクタなどの複合型である場合、 equal?は再帰的に対応する要素同士をequal?で比較してゆきます。 そうでなければ、equal?eqv?と同じようにふるまいます。

もしobj1obj2が論理値、数値、文字、ペア、文字列、 ベクタのいずれでもなく、かつ両者のクラスが等しい場合、equal?は ジェネリックファンクションobject-equal?を呼びます。 object-equal?にメソッドを定義することにより、 ユーザ定義のデータ型に対するequal?の振るまいを拡張することができます。

 
(equal? (list 1 2) (list 1 2)) ⇒ #t
(equal? "abc" "abc")           ⇒ #t
(equal? 100 100)               ⇒ #t
(equal? 100 100.0)             ⇒ #f

註: obj1obj2がともに循環構造を持っている場合、 equal?は発散する可能性があります。 かわりにisomorph? (util.isomorph - 同型判定参照) が使える かもしれません。

Generic Function: object-equal? obj1 obj2

equal?が未知のオブジェクトに対して呼ばれた場合、 このジェネリックファンクションが呼ばれます。自分で定義したクラスに対して このメソッドを定義することにより、equal?で等価判定が行えるように なります。メソッドは、obj1obj2が等価ならば#tを、 そうでなければ#fを返さねばなりません。 オブジェクトの各要素に対して再帰的に等価判定を行いたい場合は、 object-equal?を直接呼ぶのではなく、equal?を各要素に対して 呼ぶようにして下さい。

 
(define-class <foo> ()
  ((x :init-keyword :x)
   (y :init-keyword :y)))

(define-method object-equal? ((a <foo>) (b <foo>))
  (and (equal? (slot-ref a 'x) (slot-ref b 'x))
       (equal? (slot-ref a 'y) (slot-ref b 'y))))

(equal? (make <foo> :x 1 :y (list 'a 'b))
        (make <foo> :x 1 :y (list 'a 'b)))
  ⇒ #t

(equal? (make <foo> :x 1 :y (make <foo> :x 3 :y 4))
        (make <foo> :x 1 :y (make <foo> :x 3 :y 4)))
  ⇒ #t

しばしば、ふたつの複合型オブジェクトに関して、両者がトポロジー的に等しいこと、 すなわち一方が共有する部分構造を持っている場合にもう一方も同じように部分構造を 共有しているかどうかを調べたいことがあります。equal?はその目的には 使えません。モジュールutil.isomorphの提供するisomorphic?が その目的に使えます。(util.isomorph - 同型判定参照)。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.