Scheme で append 手続きを再定義(未完成)

append 手続きも再定義してみた。

(define list-append
  (lambda (a . b)
    (let loop ((a a) (b b))
      (if (null? b)
        a ; b が空リストなら a を返す
        (if (null? a) ; b が空リストじゃなくて
          (loop (car b) (cdr b)) ; a が空リストなら b の car と cdr で再帰
          (if (null? (car b)) ; a が空リストじゃなくて
            (loop a (cdr b)) ; b の car が空リストなら b の car は無視して再帰
            (if (pair? (car b)) ; b の car が空リストじゃなくて
              (let loop2 ((x a) (y (car b))) ; b の car がペアなら
                (if (null? x) ; x が空リストになるまで x の最後の要素を y にくっつけつつ
                  (loop y (cdr b)) ; y と b の cdr で再帰
                  (loop2 (reverse (cdr (reverse x))) (cons (car (reverse x)) y)))))))))))


いくつか用意したテストケースで、通らないものがある。

(equal? (list-append '()) '())
(equal? (list-append '() '() '()) '())
(equal? (list-append '(x)) '(x))
(equal? (list-append '(x) '(y)) '(x y))
(equal? (list-append '(x) '(y z)) '(x y z))
(equal? (list-append '(x y) '(z)) '(x y z))
(equal? (list-append '(a b) '(c d)) '(a b c d))
(equal? (list-append '(a) '(b c d)) '(a b c d))
(equal? (list-append '(a (b)) '((c))) '(a (b) (c)))
(equal? (list-append '(a b) '(c . d)) '(a b c . d))
(equal? (list-append '() 'a) 'a)
(equal? (list-append '(a b) 'c) '(a b . c)) ; => #f
(equal? (list-append '(a b) '(c) '(d e)) '(a b c d e))
(equal? (list-append '(a b) '() '(c d)) '(a b c d))
(equal? (list-append '() '() 'c) 'c)) ; => Error

今回は、可変長引数を扱う必要があって、これにハマッてしまい、たった十数行のコードに 3 時間以上かかった(そして完成していない)。

しかも、コメントを書かないと処理がわからなくなってしまう。たぶん複雑な条件分岐には cond を使うべきだったんだと思う。