たまには Scheme を。
Scheme で整数のリストを作るには iota 手続きが使える。
^o^ > gosh
gosh> (iota 10)
(0 1 2 3 4 5 6 7 8 9)
gosh> (iota 10 2)
(2 3 4 5 6 7 8 9 10 11)
gosh> (iota 10 2 2)
(2 4 6 8 10 12 14 16 18 20)
これを自前で実装してみよう。
最初に作ったのがこれ。可変長引数なので、引数の数に応じて対応する補助手続きを呼び出している。
(define my-iota
(lambda (n . args)
(cond ((null? args) (my-iota-simple n))
((= (length args) 1) (my-iota-start n (car args)))
(else (my-iota-step n (car args) (cadr args))))))
(define my-iota-simple
(lambda (n)
(let loop ((start 0) (i (- n 1)) (lis '()))
(if (< i start)
lis
(loop start (- i 1) (cons i lis))))))
(define my-iota-start
(lambda (n start)
(let loop ((i (- (+ start n) 1)) (lis '()))
(if (< i start)
lis
(loop (- i 1) (cons i lis))))))
(define my-iota-step
(lambda (n start step)
(let loop ((i (+ start (* (- n 1) step))) (lis '()))
(if (< i start)
lis
(loop (- i step) (cons i lis)))))) (print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2))
実行例:
^o^ > gosh my-iota.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
上の実装では3つの補助手続きを定義しているけど、内容は同じようなものなので1つにまとめることにした。つまり、引数を3つとる補助手続き my-iota-general を定義しておいて、本体手続き my-iota のほうで場合分けをして呼び出す。
(define my-iota
(lambda (n . args)
(cond ((null? args) (my-iota-general n 0 1))
((= (length args) 1) (my-iota-general n (car args) 1))
(else (my-iota-general n (car args) (cadr args))))))
(define my-iota-general
(lambda (n start step)
(let loop ((i (+ start (* (- n 1) step))) (lis '()))
(if (< i start)
lis
(loop (- i step) (cons i lis))))))
(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2))
^o^ > gosh my-iota2.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
だいぶシンプルになった。もう一歩進めてみよう。上の my-iota 手続きの中では場合分けをして my-iota-general の引数 start、step を決めているので、let で局所変数にしてしまえば my-iota-general の本体部分を取り込むことができる。
(define my-iota
(lambda (n . args)
(let ((start (if (>= (length args) 1) (car args) 0))
(step (if (>= (length args) 2) (cadr args) 1)))
(let loop ((i (+ start (* (- n 1) step))) (lis '()))
(if (< i start)
lis
(loop (- i step) (cons i lis)))))))
(print (my-iota 10))
(print (my-iota 10 2))
(print (my-iota 10 2 2))
^o^ > gosh my-iota3.scm
(0 1 2 3 4 5 6 7 8 9)
(2 3 4 5 6 7 8 9 10 11)
(2 4 6 8 10 12 14 16 18 20)
めでたく1つの手続きにできた。