Clojure `loop`and`with redefs`不能很好地配合使用
我有一些代码,我重构了这些代码,却发现有东西被Clojure `loop`and`with redefs`不能很好地配合使用,clojure,Clojure,我有一些代码,我重构了这些代码,却发现有东西被循环破坏了。经过一些调试,我发现循环和与redefs不能很好地配合使用。我意识到在循环中使用redefs可能没有意义,但我没想到它会不起作用。我不确定这是不是有意的 这是我为演示“问题”而创建的MCVE: 这给了我: 重复出现的参数计数不匹配,应为:0个参数,获得:1 使用redefs删除,的效果与预期一致: (loop [test 3] (if (zero? test) "done" (recur (dec test))))
循环
破坏了。经过一些调试,我发现循环
和与redefs
不能很好地配合使用。我意识到在循环中使用redefs可能没有意义,但我没想到它会不起作用。我不确定这是不是有意的
这是我为演示“问题”而创建的MCVE:
这给了我:
重复出现的参数计数不匹配,应为:0个参数,获得:1
使用redefs删除,
的效果与预期一致:
(loop [test 3]
(if (zero? test)
"done"
(recur (dec test))))
并返回“完成”
第一段代码不工作的原因是什么?这是故意的吗?解释是用redefs对
进行宏观扩展:
(macroexpand-1
'(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
返回:
(with-redefs-fn {}
(fn []
(if (zero? test)
"done"
(recur (dec test)))))
您可以看到,由于引入了新的fn
,因此recur
将引用该fn
,而不是更远的循环(这解释了算术异常)
还有许多其他宏以这种方式与循环
“不兼容”,因为循环
需要相对于循环
处于尾部位置,如果循环
发生在宏调用内,宏可能正在操纵代码,以使recur
不再处于尾部位置
特别是对于使用redefs的(以及各种其他情况),解决方法可以是:
(loop [test 3]
(let [[recur? val]
(with-redefs []
(if (zero? test)
[false "done"]
[true (dec test)]))]
(if recur?
(recur val)
val)))
(loop [test 3]
(let [[recur? val]
(with-redefs []
(if (zero? test)
[false "done"]
[true (dec test)]))]
(if recur?
(recur val)
val)))