正当我认为我已经很好地掌握了宏的时候,我偶然发现了some
的源代码,乍一看我觉得有点奇怪。
(defn some
[pred coll]
(when (seq coll)
(or (pred (first coll)) (recur pred (next coll)))))
我的第一个直觉是它看起来会消耗堆栈,但后来我记起:“不,dummy,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的调用会以某种方式导致新的宏调用,这是没有意义的,因为宏扩展必须在运行时之前发生。现在我想我明白我的困惑所在了,只有一个宏展开,结果代码在循环中反复使用。
发布于 2019-06-26 08:49:01
首先,请注意,任何函数都可以用作隐式loop
表达式。此外,recur
的工作方式类似于递归函数调用,只是它不会因为编译器技巧而耗尽堆栈(这就是为什么loop
和recur
是“特殊形式”--它们不遵循普通函数的规则)。
另外,请记住,when
是一个可以展开为if
表达式的宏。
说了这么多,你确实得出了正确的结论。
https://stackoverflow.com/questions/56763651
复制相似问题