begin, recur, retry

オリジナル言語の新しい文法を妄想してやまないとき、継続や末尾再帰を使いたいなら Scheme で、それ以外なら Common Lisp でマクロなり何なりを書いて実験してみるのだけれど、実際にそうやって作ってしまうと、じゃあ新言語じゃなくてこれ使えばいいじゃん、ということになって妄想は妄想のまま終わるのでした。
それはそれとして、今回のはシンプルなループ・マクロ。

(defmacro begin (&body body)
  `(begin-helper () () ,body))

(defmacro begin-helper (syms vals body)
  (if (and (>= (length body) 3)
	   (eq (second body) '=))
      `(begin-helper (,@syms ,(first body))
		     (,@vals ,(third body))
		     ,(cdddr body))
      `(block begin
	 (labels ((recur ,syms ,@body)
		  (retry ,syms
		    (return-from begin (recur ,@syms))))
	   (recur ,@vals)))))

begin ブロックの中で recur と retry という2つの局所関数を定義する。前者は普通の再帰で、後者は処理の残りを捨てて次のループに入るというC言語の continue 文みたいなイメージ。
おまけとして、ブロックの先頭で sym = val みたいな形で変数宣言を書けるようにした。recur や retry に与えた引数はこの値を更新する。
まずリストを逆順にする処理を recur で書くとこうなる:

CL-USER> (begin
	   sub = '(1 2 3)
	   acc = '()
	   (if sub
	       (recur (cdr sub)
		      (cons (car sub) acc))
	       acc))
(3 2 1)

普通の末尾再帰だ。一方、retry を使うと続きの処理がすっ飛ばされるので以下のようにも書ける:

CL-USER> (begin
	   sub = '(1 2 3)
	   acc = '()
	   (when sub
	     (retry (cdr sub)
		    (cons (car sub) acc)))
	   acc)
(3 2 1)