具有失败形式的clojure线程宏

时间:2019-03-20 10:24:17

标签: error-handling clojure

我有一些我想线程化的操作,每个操作都可能失败。我宁愿将错误作为值而不是使用try-catch来破坏执行流程。

我可以执行朴素的版本,并使函数将nil用作失败:

(if-let (op1 ...)
  (if-let (op2 ...)
    ...
    err1)
  err2)

但是它是嵌套的,很难阅读。

我可以使用some->,这似乎是最接近的解决方案,但它没有说明失败的原因:

(if-let [res (some-> arg
                     op1
                     op2)]
  res
  somethin-failed) ;; what failed though?

我也查看了->cond->,但它们似乎没有帮助。

我知道在线上有宏可以执行此类操作,但是如果有解决方案,我宁愿不添加宏。希望有某种形式:

(some-with-err-> arg
                 op1 err1
                 op2 err2
                 ...)

我可能忽略了一些简单的东西,但似乎找不到内置的东西来解决此问题。

我可以编写一个宏来执行此操作,但现在宁愿避免使用它。

1 个答案:

答案 0 :(得分:3)

没有内置的功能,但是似乎可以找到想要的单子错误处理库(例如Failjure)。

您可以从some-with-err->宏定义中导出版本some->。唯一实际的区别是,绑定到map的{​​{1}}函数现在可以对表单/错误值进行分区,将steps的调用包装在step中,并在失败时返回一个命名空间映射: / p>

try

它可以像(defmacro some-with-err-> [expr & forms] {:pre [(even? (count forms))]} (let [g (gensym) steps (map (fn [[step error]] `(if (or (nil? ~g) (::error ~g)) ~g (try (-> ~g ~step) (catch Exception _# {::error ~error})))) (partition 2 forms))] `(let [~g ~expr ~@(interleave (repeat g) (butlast steps))] ~(if (empty? steps) g (last steps))))) 一样使用,但是每种形式都必须带有错误返回值:

some->