在Clojure中有几千个条款

时间:2014-07-17 17:24:07

标签: clojure

在Clojure中运行以下代码会产生StackOverflow错误:

(cond 
 (= 1 2) 1
 (= 2 3) 2
 (= 3 4) 3

 ...

 (= 1022 1023) 1022
 (= 1023 1024) 1023
 :else 1024)

我想创建一个函数/宏,它可以处理大量子句而不会创建溢出的堆栈。

请告知我如何尝试这一点。

3 个答案:

答案 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)

要求是这样的:

  1. 给出条件和结果映射的列表,例如

    [ [cond1 r1] [cond2 r2] ...],其中

    cond1:(= 1 1)

    r1:1

  2. 查找结果 - rn - 其中condn评估为真
  3. 使用some

    解决方案在解决问题方面非常完美,但我认为我们可以避免使用宏

    (defn match [[condition result]]
      (when condition result))
    
    (some match [[(= 1 2) 100] [(= 2 3) 200] [(= 3 3) 300]])   ;; => 300