まあ、そうではありません。私はかつて実験をしました
(defmacro recurr (name bindings &body body)
(let* ((names (mapcar #'car bindings))
(restart (gensym "RESTART-"))
(temp1 (gensym))
(temp2 (gensym))
(shadows (mapcar (lambda (name) (declare (ignore name)) (gensym)) names)))
`(block ,name
(let ,bindings
(macrolet ((,name ,shadows
(list 'progn
(cons 'psetq
(loop
:for ,temp1 :in ',names
:for ,temp2 :in (list ,@shadows)
:nconcing (list ,temp1 ,temp2)))
(list 'go ',restart))))
(tagbody
,restart
(progn ,@body)))))))
そして、スキームの名前付きレットのように使用されます。例:
(recurr traverse ((list '(1 2 3 4)))
(if (null list) 'end
(traverse (cdr list))))
しかし:
- 定義されたオブジェクト (例) は関数で
traverse
はありませんfuncall
。apply
- この種の構造は、再帰構造に実際には対応していません (つまり、スタックが保持されないため、シーケンスの代わりに任意のツリーをトラバースするために使用することはできません)。
別のアプローチは
(defmacro label (name (&rest bindings) &body body)
`(labels ((,name ,(mapcar #'first bindings) ,@body))
(,name ,@(mapcar #'second bindings))))
これは実際に言及されたポイントに対処しますが、「ルックマ、スタックスペースのコンシングなし」プロパティを失います。