The King's Museum

ソフトウェアエンジニアのブログ。

Scheme 手習い(6)

第7章:友達と親類

set?

(define (set? lat)
  (cond [(null? lat) #t]
        [(member? (car lat) (cdr lat)) #f]
        [else (set? (cdr lat))]))

lat が重複要素を持たない(= セットかどうか)かを調べる関数。 前章までですでに定義した手続き member? を利用する。

makeset

(define (makeset lat)
  (cond [(null? lat) '()]
        [(member? (car lat) (cdr lat)) (makeset (cdr lat))]
        [else (cons (car lat) (makeset (cdr lat)))]))

(define (makeset lat)
  (cond [(null? lat) '()]
        [else (cons (car lat)
                    (makeset (multirember (car lat) (cdr lat))))]))

makeset の2つのバリエーション。 member? を使うか multirember を使うかでリスト内の要素の順序が変わる。 機能は同じだけど実装が異なるという話。

subset?

(define (subset? set1 set2)
  (cond [(null? set1) #t]
        [else (and (member? (car set1) set2)
                   (subset? (cdr set1) set2))]))

set1 が set2 の部分集合かどうかを調べる関数。 and をうまく使うと短く書ける。

eqset?

(define (eqset? set1 set2)
  (and (subset? set1 set2) (subset? set2 set1)))

set1 と set2 が等しい集合かどうかを調べる関数。 subset? を使うとうまく簡潔に書ける。

intersect?

(define (intersect? set1 set2)
  (cond [(null? set1) #f]
        [else (or (member? (car set1) set2)
                  (intersect? (cdr set1) set2))]))

二つの集合に共通部分があるかどうかを調べる関数。 set1 の要素が1つでも set2 にあったら true となる。

intersect

(define (intersect set1 set2)
  (cond [(null? set1) '()]
        [(member? (car set1) set2)
         (cons (car set1) (intersect (cdr set1) set2))]
        [else (intersect (cdr set1) set2)]))

二つの集合の積集合を得る関数。

union

(define (union set1 set2)
  (cond [(null? set1) set2]
        [(member? (car set1) set2)
         (union (cdr set1) set2)]
        [else (cons (car set1) (union (cdr set1) set2))]))

二つの集合の和集合を得る関数。 実装としてはちょうど intersect の反対のような処理を行う。

intersectall

(define (intersectall l-set)
  (cond [(null? (cdr l-set)) (car l-set)]
        [(intersect (car l-set) (intersectall (cdr l-set)))]))

集合のリストからすべての集合の積集合を得るための関数。 リスト内のそれぞれの集合に intersect を再帰的に適用する。 もし、集合 A、B、C、D があったら、

(intersect A (intersect B (intersect C (intersect D))))

と適用していくイメージ。((intersect D) = D である)

a-pair?

(define (a-pair? x)
  (cond [(atom? x) #f]
        [(null? x) #f]
        [(null? (cdr x)) #f]
        [(null? (cdr (cdr x))) #t]
        [else #f]))

対象がペアかどうかを調べる関数。 ペアとは Lisp における対ではなくて、要素がふたつのリストという意味。

fun?

(define (fun? rel)
  (cond [(null? rel) #t]
        [else (set? (firsts rel))]))

対象の関係(rel)が関数であるかどうかを調べる。 関数であるためには、入力(第一要素)が重複してないことが条件。

revrel

(define (revrel rel)
  (cond [(null? rel) '()]
        [else (cons
               (build (second (car rel))
                      (first (car rel)))
               (revrel (cdr rel)))]))

対象の関係(rel)を逆にする関数。 第一要素と第二要素を入れ替えて、リストを構築し直す。

fulfun?

(define (fullfun? rel)
  (cond [(null? rel) #t]
        [else (set? (seconds rel))]))

第二要素に重複がないかどうかを調べる関数。

one-to-one?

(define (one-to-one? rel)
  (fun? (revrel fun)))

full-fun? を fun? と revrel を使って書き直した関数。 one-to-one は単射の意味(だと思う)。

感想

集合の操作がメイン。難しいところはそんなになかったかな。

最近、進捗があまりよくないなぁ。

次章からが本番な気がする。

(c) The King's Museum