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)