さかもとのブログ

つらつらと

同じ文字をまとめる

common lispでの実装を通して,schemeとの違いが書かれている.
このページに

(pack '(a a a a b c c a a d e e e e))
((A A A A) (B) (C C) (A A) (D) (E E E E))

と結果が返ってくるような関数packが載っていたので,schemeでやってみた.

(define (pack lis)
  (pack-first lis))

(define (pack-first lis)
  (if (null? lis)
      '()
      (let ((x (car lis))
            (y (cadr lis)))
        (if (equal? x y)
            (pack-core (cddr lis) (list x y) '())
            (pack-core (cdr lis) (list x) '())))))

(define (pack-core lis tmp-lis result)
  (if (null? lis)
      (append result (list tmp-lis))
      (let ((x (car lis))
            (y (car tmp-lis)))
        (if (equal? x y)
            (pack-core (cdr lis) (append tmp-lis (list y)) result)
            (pack-core (cdr lis) (list x) (append result (list tmp-lis)))))))
(pack '(a a a d b b c c a a))
;=> ((a a a) (d) (b b) (c c) (a a))

ひとつの関数でできるんだけれど,今回はあえてばらした.なぜかというと,うえのページに書いてあったんだけど,

traceで局所関数を追うのは難しいんで、局所関数はデバッグ向けじゃない

まさにSICPで苦しんだのがこれで,letで内部的に定義したものにバグがあると,見つけるのがかなりきつい.
なので,今回は一応ばらして書いた.
しかし...もうちょっとまとめられるだろ.pack-firstとpack-coreはtmp-lisが空の場合とそうでない場合なだけの違いなのだから..