2010/05/15

defmacro while

do マクロの使い方を覚えられないクラスタです。
再帰で書いてみましたが、do マクロ版と同等かよくわかりません。

上が、On Lisp に載ってる版。下が再帰版。
;; while
(defmacro my-while (test &body body)
`(do ()
((not ,test))
,@body))
(let ((i 0))
(my-while (< i 10)
(print i)
(setf i (+ i 1))))
(defmacro my-while2 (test &body body)
`(labels
((self ()
(if ,test
(progn
,@body
(self)))))
(self)))
(let ((i 0))
(my-while2 (< i 10)
(print i)
(setf i (+ i 1))))

追記

最基盤再帰版は戻り値が常に nil ですね(笑)

追記2

格好悪いですが、これなら?
(defmacro my-while2 (test &body body)
`(labels
((self ()
(if ,test
(prog1 (progn
,@body)
(self)))))
(self)))

追記3

nil で良かった件。

追記4

prog1 の方もちゃんと戻ってないですね(笑)

追記5


@valvallow 暗黙の block と tagbody が無いので、return や return-from や go が使えない点がホンモノと違うかも?less than a minute ago via Tween



追記6

(defmacro my-while (test &body body)
;; テンプレートの外部で var0、var1 で gensym を束縛する
(let ((var0 (gensym)) (var1 (gensym)))
`(do ((,var0 nil ,@(last body))
(,var1 nil ,var0))
((not ,test) ,var1)
,@(butlast body))))
view raw my-while.lisp hosted with ❤ by GitHub

(defmacro! my-while! (test &body body)
`(do ((,g!var0 nil ,@(last body))
(,g!var1 nil ,g!var0))
((not ,test) ,g!var1)
,@(butlast body)))
view raw my-while!.lisp hosted with ❤ by GitHub

(defmacro my-while2 (test &body body)
(let ((self (gensym)) (exp (gensym)) (acc (gensym)))
`(labels
((,self (,exp ,acc)
(if (not, test)
,acc
(,self (progn ,@body) ,exp))))
(,self (progn ,@body) nil))))
(defmacro! my-while2! (test &body body)
`(labels
((,g!self (,g!exp ,g!acc)
(if (not ,test)
,g!acc
(,g!self (progn ,@body) ,g!exp))))
(,g!self (progn ,@body) nil)))

On Lisp

0 件のコメント:

コメントを投稿