SRFI-1のiotaっぽいものをCommon Lispで書き直してみた

SRFI-1のiotaっぽいものを自作したのは半分以上趣味だけど、Common Lispに書き換えるのは4分の3以上趣味だと主張しておく。

というか、Common Lispの仕様は無茶苦茶大きいらしいので、もしかしたら似たような関数が既にあるかもしれない。でもまあ、成長の為には時として車輪の再発明も必要だと個人的には考えているので*1、後悔はしていない。

; 再帰版
(defun iota (count &optional (start 0) (step 1))
  (if (<= count 0)
      '()
      (cons start (iota (- count 1) (+ start step) step))))

; 末尾再帰(反復)版
(defun iota (count &optional (start 0) (step 1))
  (labels ((iota-iter (count num list)
             (if (<= count 0)
                 (reverse list)
                 (iota-iter (- count 1) (+ num step) (cons num list)))))
    (iota-iter count start '())))

; 末尾再帰(反復)版の trace対応バージョン
; (trace iota-iter) してからiotaを呼べばOK
(defun iota-iter (count start step list)
  (if (<= count 0)
      (reverse list)
      (iota-iter (- count 1) (+ start step) step (cons start list))))

(defun iota (count &optional (start 0) (step 1))
  (iota-iter count start step '()))

例によってエラー処理とかは考慮していない。*2

それにしても、やっぱりSchemeCommon Lispは別物だと感じた。

  • 見ての通り、関数定義の方法が異なる。
  • オプション引数用の記法が用意されている。
  • 関数内でdefunで定義した関数も外から見える*3。局所関数を定義する場合はlabelsを使うみたい。

SchemeCommon Lisp、どっちを勉強しようか益々迷ってきた。

*1:でも仕事では車輪の再発明は避けたいと思う今日この頃。

*2:Common Lispならエラー処理用の関数とかが用意されてそうだけど、どうなんだろう?

*3:そもそもdefunで定義した関数は大域関数になるらしい