My開発メモ

繰返し処理 do (Common-Lisp)

『On Lisp』( http://www.asahi-net.or.jp/~kc7k-nd/onlisp_j.pdf )
を読んでたら、以下のようなコードが出てきて、5日間ほど悩んだ。

defun split-if (fn lst)
  (let ((acc nil))
    (do ((src lst (cdr src)))
        ((or (null src) (funcall fn (car src)))
         (values (nreverse acc) src))
      (push (car src) acc))))
CL-USER> (split-if #'(lambda (x) (> x 4))
                   '(1 2 3 4 5 6 7 8 9 10))

(1 2 3 4)
(5 6 7 8 9 10)

悩んだところというのは、次の箇所。

(do ((src lst (cdr src)))  ... )

src という変数を lst で初期化しているのはわかるのだけど、
次の (cdr src) が何なのか、わからなかった。

これはつまり、更新処理だというのがわかったのは、以下のサイトの記述を見たから。

[Common Lisp] メモ: defconstant, boundp, do, dolist

この do の書き方を知らなかったので、メモしておく。

(do ((変数 初期値 更新方法))
    ((終了条件) (戻り値))
  (繰り返し処理))

要するに、C言語などの for()文みたいなものかな。

ついでに、再帰で書き直してみた。

(defun split-if* (fn lst)
  (let ((src lst))
    (labels
        ((rec (src acc)
           (if
            (or (null src) (funcall fn (car src)))
            (values (nreverse acc) src)
            (rec (cdr src) (cons (car src) acc)))))
      (rec src nil))))

カテゴリー: Lisp, memo

タグ: common-lisp, do, Lisp, On Lisp, 繰り返し

カウント: 118