在Clojure中运行以下代码会产生StackOverflow错误:
(cond
(= 1 2) 1
(= 2 3) 2
(= 3 4) 3
...
(= 1022 1023) 1022
(= 1023 1024) 1023
:else 1024)
我想创建一个函数/宏,它可以处理大量子句而不会创建溢出的堆栈。
请告知我如何尝试这一点。
答案 0 :(得分:5)
如果查看完整堆栈跟踪,您会看到cond
发出深层嵌套的if
结构;当编译器尝试解析此结构时,会发生异常。问题可能与简单编译深层嵌套的Clojure代码有关,而不是cond
的具体用法。
我能够提出以下宏来获取子句列表,将它们包装在thunk中以提供if
所带来的延迟评估,然后使用some
查找第一个逻辑真实的测试表达由于创建了如此多的匿名函数,它的性能可能不是那么好,但它会绕过堆栈溢出异常。
(defmacro cond' [& clauses]
`(:result
(some (fn [[pred-thunk# val-thunk#]]
(if (pred-thunk#) {:result (val-thunk#)}))
(partition 2 (list ~@(map (fn [c] `(fn [] ~c)) clauses))))))
请注意在映射中包装和展开返回的值,以确保some
正确处理计算结果为nil的值子句。
答案 1 :(得分:5)
cond
有513个条款,不太可能在实践中使用。
以下是您的示例的功能实现。
(or (some identity (map #(if (= %1 %2) %1)
(range 1 1024)
(range 2 1025)))
1024)
答案 2 :(得分:0)
要求是这样的:
给出条件和结果映射的列表,例如
[ [cond1 r1] [cond2 r2] ...]
,其中
cond1:(= 1 1)
,
r1:1
rn
- 其中condn
评估为真some
的解决方案在解决问题方面非常完美,但我认为我们可以避免使用宏。
(defn match [[condition result]]
(when condition result))
(some match [[(= 1 2) 100] [(= 2 3) 200] [(= 3 3) 300]]) ;; => 300