我有一些代码,我重构只是为了找出被破坏的东西loop
.经过一些调试后,我发现loop
并且with-redefs
不能很好地一起玩.我意识到with-redefs
在循环中使用它可能没有意义,但我没想到它不起作用.我不确定它是否有意.
这是我创建的MCVE,用于演示"问题":
(loop [test 3]
(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
Run Code Online (Sandbox Code Playgroud)
这给了我:
不匹配的参数计数重复,预期:0 args,得到:1
with-redefs
按预期删除工作:
(loop [test 3]
(if (zero? test)
"done"
(recur (dec test))))
Run Code Online (Sandbox Code Playgroud)
并返回"done"
.
第一段代码不起作用的原因是什么?这是故意的吗?
解释是在宏观扩展中with-redefs
:
(macroexpand-1
'(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
Run Code Online (Sandbox Code Playgroud)
收益:
(with-redefs-fn {}
(fn []
(if (zero? test)
"done"
(recur (dec test)))))
Run Code Online (Sandbox Code Playgroud)
在那里你可以看到,因为fn
引入了一个新的,recur
它将引用它fn
而不是更远的地方loop
(这解释了arity异常).
有多种是"不相容"与其他宏loop
以这种方式,因为recur
需要将在相对于所述末尾位置loop
,并且如果recur
一个宏调用内部发生,宏可以是操纵代码,使得recur
是不再处于尾部位置.
对于with-redefs
特别是(和各种其他情况),一种解决方法可以是:
(loop [test 3]
(let [[recur? val]
(with-redefs []
(if (zero? test)
[false "done"]
[true (dec test)]))]
(if recur?
(recur val)
val)))
Run Code Online (Sandbox Code Playgroud)