たまには 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つの手続きにできた。