Recursion macrolet是否禁止在本地定义的宏之间进行递归调用?
保罗·格雷厄姆(Paul Graham)在他的书(第320页)中写道:“就像Recursion macrolet是否禁止在本地定义的宏之间进行递归调用?,recursion,macros,common-lisp,Recursion,Macros,Common Lisp,保罗·格雷厄姆(Paul Graham)在他的书(第320页)中写道:“就像flet,本地宏可能不会相互调用。” 也许我误解了这一点,但我想不出哪种方式是真的。宏之间不相互调用,而是相互展开,宏展开的性质是,它将继续展开,直到范围中定义的所有宏都展开为止 在我尝试过的每个Common Lisp实现中,下面这样的代码都与Graham不一致: (macrolet ((jump (x) `(car ,x)) (skip (x) `(jump ,x)) (ho
flet
,本地宏可能不会相互调用。”
也许我误解了这一点,但我想不出哪种方式是真的。宏之间不相互调用,而是相互展开,宏展开的性质是,它将继续展开,直到范围中定义的所有宏都展开为止
在我尝试过的每个Common Lisp实现中,下面这样的代码都与Graham不一致:
(macrolet ((jump (x) `(car ,x))
(skip (x) `(jump ,x))
(hop (x) `(skip ,x)))
(hop '(1 2 3)))
=> 1
(macrolet ((yin (n x)
(if (zerop n)
`(cdr ,x)
`(yang ,(1- n) ,x)))
(yang (n x)
(if (zerop n)
`(car ,x)
`(yin ,(1- n) ,x))))
(yin 6 '(1 2 3)))
=> (2 3)
格雷厄姆的陈述有错误吗?由
macrolet
定义的宏可以扩展到使用同一macrolet
中定义的不同宏。由macrolet
定义的宏直接使用在同一macrolet
中定义的不同宏是不正确的。例如:
(macrolet ((jump (x) `(car ,x))
;; Okay since skip expands into jump.
(skip (x) `(jump ,x)))
(skip '(1 2 3)))
=> 1
相对于
(macrolet ((jump (x) `(car ,x))
;; Wrong since skip uses jump directly.
(skip (x) (jump x)))
(skip '(1 2 3)))
=> Error: The function COMMON-LISP-USER::JUMP is undefined.
我认为这不是一个错误,有着未定义的后果:“由macrolet定义的宏扩展函数是在macrolet表单出现的词汇环境中定义的。声明、macrolet和symbol macrolet定义会影响macrolet中的本地宏定义,但如果本地宏定义引用在该词法环境中可见的任何本地变量或函数绑定,则结果是未定义的。“我认为这意味着,由于宏定义函数位于词法环境中,引用它们将是……引用在该词法环境中可见的局部变量或函数绑定。引用的文本来自@JoshuaTaylor,这不相关,该段落的意思是本地宏不能使用词汇变量和函数。基本上,这只是解释了一个常见的错误,即开发人员忘记了宏在运行前扩展为代码,可能是在单独的编译时阶段。换句话说,
let
、let*
、flet
和labels
定义运行时可用于代码的局部变量和函数,而macrolet
和symbol macrolet
定义运行前预处理阶段可用于代码扩展的局部宏,ANSI规范省略了macrolet
的递归能力(缺乏),这可以解释通常实现的非递归行为。该语句在给定的情况下是有问题的,因为它没有指定任何关于macrolet
定义是否是相互递归的。但是,根据所描述的内容,您可以理解历史背景。