星にゃーんのブログ

ほとんど無害。

iotaからunfoldをつくる Common Lisp編

まず、iotaを定義する。 簡潔にするため、オプション引数は使わない。

(defun iota (limit seed step)
  (if (> seed limit)
    nil
    (cons seed (iota limit (+ seed step) step))))

(> seed limit)を一般化して、終了条件を指定できるよう変更する。

(defun func1 (pred seed step)
  (if (funcall pred seed)
    nil
    (cons seed (func1 pred (+ seed step) step))))

(+ seed step)を一般化して、seedの変化を指定できるよう変更する。

(defun func2 (pred next-gen seed)
  (if (funcall pred seed)
    nil
    (cons seed (func2 pred next-gen (funcall next-gen seed)))))

最後に、mapcar関数と合成する。

(defun func3 (pred fn next-gen seed)
  (if (funcall pred seed)
    nil
    (cons (funcall fn seed)
          (func3 pred fn next-gen (funcall next-gen seed)))))

もっと単純に、こうしてもいい。

(defun func3 (pred fn next-gen seed)
  (mapcar fn (func2 pred next-gen seed)))

これでunfold関数の完成。

(defun unfold (p f g n)
  (if (funcall p n)
    nil
    (cons (funcall f n)
          (unfold p f g (funcall g n)))))

参考URL