【发布时间】:2019-11-07 20:37:08
【问题描述】:
就在我认为自己对宏有相当好的处理能力时,我偶然发现了some 的源代码,乍一看我觉得有点奇怪。
(defn some
[pred coll]
(when (seq coll)
(or (pred (first coll)) (recur pred (next coll)))))
我的第一直觉是这似乎会消耗堆栈,但后来我记得:“不,笨蛋,or 是一个宏,所以它会简单地扩展成大量嵌套的ifs”。
然而,我仔细考虑了一下,最终认为自己在一个角落里。在扩展时,函数源如下所示:
(defn some
[pred coll]
(when (seq coll)
(let [or__4469__auto__ (pred (first coll))]
(if or__4469__auto__
or__4469__auto__
(recur pred (next coll))))))
现在让我感到困惑的是最后的recur 电话。我一直认为宏扩展发生在运行时之前,但是在这里您必须在运行时实际调用已经扩展的代码才能进行第二个宏扩展....等一下,我想我刚刚弄明白了。
没有第二个宏扩展,没有嵌套的if 块,只有一个if 块。对recur 的调用只是不断重新绑定pred 和coll,但上面的同一个块一直在测试真相,直到找到它,或者集合用完并返回nil。
有人可以确认这是否是正确的解释吗?我最初感到困惑,认为宏扩展和运行时会有交错,其中在运行时对 recur 的调用会以某种方式导致新的宏调用,这没有意义,因为宏扩展必须在运行时之前发生。现在我想我明白了我的困惑在哪里,只有一个宏扩展,并且生成的代码在循环中一遍又一遍地使用。
【问题讨论】: