欢迎!请查看 关于 页面以获取更多关于如何使用本网站的信息。
评论者:michalmarczyk
这是一个关于“关键字循环名称”补丁的初步版本
0002-CLJ-2235-use-keywords-as-loop-names.patch
此补丁将应用于“分开的特殊形式”补丁之上
0001-CLJ-2235-implement-named-loop-recur-to-separate-special-form.patch
同时附上压缩补丁以方便
0001-CLJ-2235-recur-to-keyword-loop-names.patch
以下是新方案的一个示例
`(let [m [[[1 2 3] [4 5 6] [7 8 9]]
`
[[10 11 12] [13 14 15] [16 17 18]] [[19 20 21] [22 23 24] [25 26 27]]]] ((fn iloop [i ires] (if (== i (count m)) ires (loop :jloop [j 0 jres 0] (if (== j (count (get m i))) (recur-to iloop (inc i) (+ ires jres)) (loop [k 0 kres 0] (if (== k (count (get-in m [i j]))) (recur-to :jloop (inc j) (+ jres kres)) (recur (inc k) (+ kres (get-in m [i j k]))))))))) 0 0))
请注意,当目标为fn形式时,recur-to仍然使用符号。
此外,需要注意的是,在此补丁中采用的这种方法有一个副作用,即名为:foo的循环名称不会覆盖名为foo的fn引入的recur目标。如果我们最终要引入以符号为名的非fn引入的recur目标(如前一个评论中讨论的 recur-to-targetable Scheme-style let/loop形式),那么这绝对是一个可行的办法。如果不是这样,也许这比在当前上下文中声明:foo会覆盖foo少一些任意性?
我在尝试此补丁时发现一个不幸的不兼容性问题。以下代码编译失败,错误信息为"No matching recur/recur-to target"(没有匹配的recur/recur-to目标)
(defn example [x] (loop top [] (case (int x) 0 (loop [] (recur-to top)))))
查看Compiler.java,我认为问题是,在这种情况下,case表达式的分支使用了C.EXPRESSION,而不是传播传递给CaseExpr.emit的上下文(在这种情况下应该是C.RETURN)。这个上下文导致recur-to忽略外部循环
对于一个未打补丁的Compiler.java中的常规recur,它看起来tail position检查是在RecurExpr.parse期间完成的。看起来CaseExpr.parse传播了上下文,因此尾调用位置检查通过。所以下面的代码可以编译而不出现错误
(defn example2 [x] (loop top [] (case (int x) 0 (loop [] (recur)))))