我正在尝试coding challenge,要求您创建无限编译的代码。
我的第一个想法是一个永远扩展到自己的宏。我写了:
(defmacro a []
(a))
(a)
这实际上并没有产生任何东西,但我预计它会永远循环。相反,我得到一个荒谬的arity异常:
Wrong number of args (-2) passed to: infinite-compile/a, compiling:...
如果我试图给它一个踢球的论据,它现在抱怨宏并不期望任何争论。
如果我有它实际上产生了对自己的调用:
(defmacro a []
`(a))
(a)
它失败了StackOverflow,我预料到了。
这里发生了什么?为什么我认为我通过宏" -2"参数呢?我能想到的唯一可能的事情是它与传递给宏的2个隐式&
参数有关,但这只是在黑暗中的一个镜头并没有实际解释发生了什么事。
为了解决这个问题,这似乎不是多方宏的一个问题,因为它只有一个0-arity版本。另外,显式传递隐式参数并没有做任何事情:
(defmacro a []
(a &form &env))
这会产生:
Compiler Exception clojure.lang.ArityException: Wrong number of args (2) passed to: infinite-compile/a, compiling:
答案 0 :(得分:2)
您期望在(a)
的定义期间a
进行宏扩展,而a
尚未知道是宏(因此预期是函数),而当你引用表格,你正在有效地建立一个宏,它扩展成对自己的呼唤。
当编译器宏扩展宏时,它会在调用与宏关联的函数之前添加隐式参数:Compiler.java#L6795。在这里,您直接调用a
,它位于隐式defn
(core.clj#L452)的范围内,而不传递必要的参数。
我希望以下内容可以按照您的意愿工作(循环):
user=> (defmacro a[]&form)
#'user/a
user=> (a)
但不幸的是,这是我收到的错误消息:
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
NB。 Common 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)
答案 1 :(得分:-1)
有关问题的更多说明,请参阅http://dev.clojure.org/jira/browse/CLJ-1279上的故障单。