set!

set! は変数への束縛を、別の値を指すように変更する。つまり代入。

gosh> (define x 1)
x
gosh> x
1
gosh> (set! x 10)
10
gosh> x
10

set! のもうひとつの形式は「一般化されたset!」で、 (set! (proc arg …) expression) という形をしていて、(proc arg …) の結果が expression に置き換えられる。

gosh> (define x (list 1 2))
x
gosh> x
(1 2)
gosh> (set! (car x) (list 10 20))
#<undef>
gosh> x
((10 20) 2)

uniq

重複する要素を削除する uniq。ソートされているのが前提。

(define uniq
  (lambda (lis)
    (let loop ((e (car lis)) (l (cdr lis)))
      (cond
        ((null? l) (list e))
        ((eq? e (car l)) (loop e (cdr l)))
        (else (cons e (loop (car l) (cdr l))))))))

(print (uniq '(1 1 1 2 3 3)))
takatoh@nightschool $ gosh uniq.scm
(1 2 3)

リストのリストを引数にとって、car がユニークになるような手続き。

(define uniq-car
  (lambda (lis)
    (let loop ((e (car lis)) (l (cdr lis)))
      (cond
        ((null? l) (list e))
        ((eq? (car e) (caar l)) (loop e (cdr l)))
        (else (cons e (loop (car l) (cdr l))))))))

(print (uniq-car '((1 1) (1 2) (2 1) (2 2) (2 3) (3 1))))
takatoh@nightschool $ gosh uniq-car.scm
((1 1) (2 1) (3 1))

もう少し進んで、比較する方法を引数で渡せるようにしてみる。

(define uniq-in
  (lambda (proc lis)
    (let loop ((e (car lis)) (l (cdr lis)))
      (cond
        ((null? l) (list e))
        ((eq? (proc e) (proc (car l))) (loop e (cdr l)))
        (else (cons e (loop (car l) (cdr l))))))))

(print (uniq-in car '((1 1) (1 2) (2 1) (2 2) (2 3) (3 1))))
(print (uniq-in cadr '((1 1) (2 1) (3 1) (1 2) (2 2) (1 3))))
takatoh@nightschool $ gosh uniq-in.scm
((1 1) (2 1) (3 1))
((1 1) (1 2) (1 3))