Clojure 递归宏中的负算术异常

Clojure 递归宏中的负算术异常,clojure,macros,arity,Clojure,Macros,Arity,我正在尝试一个要求您创建无限编译的代码的方法 我的第一个想法是一个永远自我扩展的宏。我写道: (defmacro a [] (a)) (a) 这实际上不会产生任何结果,但我希望它会永远循环。然而,我得到了一个荒谬的算术例外: Wrong number of args (-2) passed to: infinite-compile/a, compiling:... 如果我试图给它一个kicks参数,它现在会抱怨宏不需要任何参数 如果我让它实际产生对自身的调用: (defmacro a

我正在尝试一个要求您创建无限编译的代码的方法

我的第一个想法是一个永远自我扩展的宏。我写道:

(defmacro a []
    (a))
(a)
这实际上不会产生任何结果,但我希望它会永远循环。然而,我得到了一个荒谬的算术例外:

Wrong number of args (-2) passed to: infinite-compile/a, compiling:...
如果我试图给它一个kicks参数,它现在会抱怨宏不需要任何参数

如果我让它实际产生对自身的调用:

(defmacro a []
    `(a))
(a)
它失败了,出现了堆栈溢出,这是我所期望的

这是怎么回事?为什么它认为我在传递宏“-2”参数?我能想到的唯一可能的事情是,它与传递给宏的两个隐式
&
参数有关,但这只是一个猜测,并不能真正解释发生了什么

为了解决这个问题,多算术宏似乎没有问题,因为它只有0算术版本。此外,显式传递隐式参数也没有任何作用:

(defmacro a []
    (a &form &env))
这将产生:

Compiler Exception clojure.lang.ArityException: Wrong number of args (2) passed to: infinite-compile/a, compiling:
在定义
a
的过程中,当
a
尚不为人所知是一个宏(因此被期望是一个函数)时,您期望
(a)
被宏扩展,而当您引用表单时,您实际上是在构建一个宏,该宏扩展为对自身的调用

编译器宏展开宏时,会在调用与宏关联的函数之前添加隐式参数:。这里,您直接调用
a
,它在隐式
defn
()的范围内,而不传递必要的参数

我希望以下各项能够如您所愿工作(循环):

但不幸的是,我得到的错误信息如下:

CompilerException java.lang.RuntimeException: Can't take value of a macro: #'user/a, compiling:(/tmp/form-init5239882861501900074.clj:1:1) 
。。。尽管:

user=> (defmacro a[](print &form))
#'user/a
user=> (a)
(a)nil
注意。常见的Lisp等价物是:

(defmacro w(&whole w)w) ;; 23 bytes
现有名称 还请注意,一旦定义了
a
,就不能按如下方式更改定义:

(defmacro a[](a 0 1))
。。。因为它抱怨
a
接受零参数。但是,如果您使用尚未定义的名称定义另一个宏,则该宏将起作用:

user=> (defmacro b[](b 0 1))
#'user/b
user=> (b)

StackOverflowError   user/b (form-init5239882861501900074.clj:1)

有关此问题的更多描述,请参见。

上的问题单。由于我显然不太了解宏是如何实现的,因此仍然有点困惑,但这通常是有意义的。谢谢。宏只需获取代码并发出代码(另请参见)。但是你发现了一些角落案例,这些案例的行为不一定是直观的,也不一定是明智的。我理解这一部分。你提到了“隐式定义”。
defmacro
是否发出
defn
?也许我会再次查看
defmacro
的源代码。@carcigenitate
(list'do'defn…
部分生成定义函数并声明名称绑定到宏的代码。例如,该代码可能是由编译器评估的(未检查)。这不是堆栈溢出标准的答案。作为对问题或现有答案的评论,或者如果您在此处另外总结了在该链接中找到的重要内容,则会有所帮助。
user=> (defmacro b[](b 0 1))
#'user/b
user=> (b)

StackOverflowError   user/b (form-init5239882861501900074.clj:1)