gpt4 book ai didi

recursion - 如何管理 Common Lisp 宏中的递归

转载 作者:太空宇宙 更新时间:2023-11-03 18:55:54 25 4
gpt4 key购买 nike

我需要编写一个带有符号和列表的 Common Lisp 宏。该列表由两个元素的列表组成:一个符号和一个字符串,如下所示:

((X "foo") (Y "bar") (Z "qwerty"))

宏递归地工作,它在列表中搜索符号,如果找到 symbol 返回 T,否则返回 NIL。我写这段代码:

(defmacro already-exist (symbol my-list)
(cond ((null (eval my-list)) NIL)
((eql (caar (eval my-list)) symbol)
T)
(T `(already-exist symbol ,(cdr (eval my-list))))))

但问题出在递归部分。事实上,如果我尝试使用一个没有 symbol 作为第一个元素的一部分的列表来运行宏,我会得到一个错误。例如:

(defparameter listt '((X "foo") (Y "bar") (Z "qwerty")))

(already-exist Y listt)

我得到的错误是“非法函数调用”。我认为这是因为宏试图将 Y 评估为函数调用。我该如何解决这个问题?一般来说,在 Common Lisp 中编写递归宏的最佳方法是什么?

最佳答案

I need to write a Common Lisp macro [...] The macro works recursively.

您并不是真的需要宏,事实上,如果您的值仅在运行时已知,宏就无法解决问题。如果您希望符号不被计算,则需要引用符号。

... (eval my-list) ...

从宏调用 eval 是一种很大的代码味道。您的宏正在处理代码,list 符号此时除了它是一个符号之外没有任何意义。宏很可能不会list 绑定(bind)到有意义的值的环境中展开(此外,eval 在 null 中工作词汇环境)。

可以递归展开,但宏本身不是递归的:

* (defmacro foo (x) (foo x))
; in: DEFMACRO FOO
; (FOO X)
;
; caught STYLE-WARNING:
; undefined function: FOO
;
; compilation unit finished
; Undefined function:
; FOO
; caught 1 STYLE-WARNING condition
STYLE-WARNING:
FOO is being redefined as a macro when it was previously assumed to be a function.
* (foo 3)

debugger invoked on a UNDEFINED-FUNCTION in thread
#<THREAD "main thread" RUNNING {100399C503}>:
The function COMMON-LISP-USER::FOO is undefined.

宏展开以定点方式应用:从代码 X0 开始,将 X1 计算为 X0 的宏展开,并继续直到不再有任何宏展开。您的宏不会调用自身,宏扩展工具会在每次通过后根据需要经常调用它(这也是您无法在宏扩展期间建立动态绑定(bind)的原因,除非您手动调用 macroexpand)。

不过,您可以将宏扩展为同样调用宏的代码。但是你必须小心它不能无条件地这样做,否则你将有一个无限的宏扩展。

如果 list 是一个仅在运行时已知的值,您需要编写一个常规函数。基本上,你想做的是:

(member symbol list :key #'first)

参见 MEMBER , MACROEXPAND .

关于recursion - 如何管理 Common Lisp 宏中的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45881982/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com