Clojure线程宏与故障表单

3

我有几个操作需要进行线程处理,每个操作都可能失败。我更希望将错误作为值返回,而不是使用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
                 ...)

我可能忽略了更简单的方法,但似乎找不到内置的解决方案。

我可以编写一个宏来解决这个问题,但现在宁愿避免使用它。


2
你可能想看一下这个 - akond
1个回答

4

这方面没有内置功能,但有一些单子错误处理的库(例如Failjure),似乎是您正在寻找的。

您可以从some->宏定义中导出版本some-with-err->。唯一的实际区别是现在绑定到stepsmap函数将表单/错误值分区,将step调用包装在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->一样使用,但是每种形式都必须伴随一个错误返回值:
(some-with-err-> 1
  (+ 1) :addition
  (/ 0) :division
  (* 2) :multiplication)
=> #:user{:error :division}

(some-with-err-> " "
  (clojure.string/trim) :trim
  (not-empty) :empty
  (str "foo") :append)
=> nil ;; from not-empty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接