約数を求める

(define nil '())

(define (element-of-set? x set)
  (cond ((null? set) #f)
        ((equal? x (car set)) #t)
        (else (element-of-set? x (cdr set)))))

(define (uniq set)
  (define (iter x s)
    (if (null? x)
        s
        (iter (cdr x)
              (if (element-of-set? (car x) s)
                  s
                  (cons (car x) s)))))
  (iter set nil))

(define (subsets s)
  (if (null? s)
      (list nil)
      (let ((rest (subsets (cdr s))))
        (append rest (map (lambda (x) (cons (car s) x)) rest)))))

(define (divisor facts)
  (cons 1
        (sort (map (lambda (x) (apply * x)) (uniq (cdr (subsets facts)))))))

結論から言うと、こんなプログラムになります。
12 の約数を求めてみます。12 を素因数分解すると 2 * 2 * 3 になるので、
'(2 2 3) を divisor 手続きの引数に与えて評価します。

gosh> (divisor '(2 2 3))
(1 2 3 4 6 12)

素因数から約数を求めるロジックは、素因数リストから、すべての部分集合を求めて、
それぞれの部分集合の要素を掛け算すれば求めることができます。
各手続きは、

subsets は、集合 s の部分集合をすべて求める
uniq は集合 set から重複を取り除く
element-of-set? は集合 set に x を含むか調べる

となっています。
subsets はすべての部分集合を求めます。集合 '(a b c) の場合は、

gosh> (subsets '(a b c))
(() (c) (b) (b c) (a) (a c) (a b) (a b c))

このようになります。
並びの見た目がちょっと悪いですが、これがすべての部分集合です。
空の集合 '() と、自分自身 '(a b c) も部分集合に含むことに注意してください。


素因数分解のプログラムは別の機会に気が向いたら掲載したいと思います。