vector-append を実装してみた
R5RS では
(length list) (string-length string) (vector-length vector)
のようにデータ構造によって手続きが分かれている。
これが気に入らない。
Haskell の length や Python の len のように「長さを求める」という抽象化された手続きがひとつにまとまっていたほうがコードがすっきりする(ということで作ったのが Scheme で length 手続きを再実装 - satosystemsの日記)。
(append list ...) (string-append string ...)
append もデータ構造で手続きが分かれている。そして vector 用の手続きがないのもムズムズする。
Scheme の vector は、C++ や Java などのそれと違い可変長ではない(可変長は list)。どちらかというと配列のイメージが近い。なので append がないのだと思う。
でもあえて、vector-append を作ってみることにする。
(define vector-append (lambda (a . b) (list->vector (append (vector->list a) b))))
たぶんこれがもっとも正解に近いはず。
(define vector-append2 (lambda (a . b) (let ((v (make-vector (+ (vector-length a) (length b))))) (let loop ((i 0)) (if (< i (vector-length a)) ((vector-set! v i (vector-ref a i)) (loop (+ i 1))) ((if (< i (+ (vector-length a) (length b))) ((vector-set! v i (list-ref b (- i (vector-length a)))) (loop (+ i 1))) v)))))))
list->vector と vector->list を使わないバージョンも作ってみたけど、期待通りに動作しない。そしてその原因がよくわからない。
作ってみてわかったんだけど、vector-append はたとえば
(define v #(1 2 3)) (print (vector-append v 4 5)) (print v)
という風にしてみれば一目瞭然で、元の v に要素が追加できていない。C の realloc みたいな使い方をしたいんだけど Scheme ではそういうことができないので、vector-append は R5RS には含まれないのだ、と解釈した。
なお、後で気がついたんだけど SRFI 43: Vector Library に SRFI-43 として vector-append が提案されていた。僕の考える仕様とはちょっと異なるんだけど、こちらの仕様もやっぱり新たに vector を割り当てるようになっているので、やっぱり vector の動的拡張は無理みたい。