在累积所有违规行为的同时在 Clojure 中进行多项检查的最佳方法
Best way to do multiple checks in Clojure while accumulating all violations
我有几个 Clojure 谓词,它们根据不同的业务规则验证应用程序输入。考虑到这一点,我想知道遍历这一系列谓词的最佳策略是什么:
- 我不想使用例外,因为违规是预期的。
->some
将不起作用,因为它只会出现第一个 nil
。而我需要将所有的违规推送到一个违规集合中。
我考虑过以下方法,但我对此表示怀疑。
(defn validate [arg]
(cond
(logic/check-one? arg) (add-violation-one)
(logic/check-two? arg) (add-violation-two)))
一种方法是使用 cond->
。它运行所有检查并且它
向下传递分支的结果。例如
(let [arg 42
add-error #(update %1 :errors conj %2)]
(cond-> {:errors []}
(even? arg) (add-error "must not be even")
(odd? arg) (add-error "must not be odd")
(zero? arg) (add-error "must not be zero")
(pos? arg) (add-error "must not be positive")))
; → {:errors ["must not be even" "must not be positive"]}
这种方法最有意义,如果你真的想写出那些
手工的东西。不直接依赖可能更灵活
来自核心的东西并编写你自己的功能。例如。你可以减少
在谓词和错误处理程序的元组上。
(defn validate
[checks errors arg]
(reduce
(fn validation-step [errors [pred handle-error]]
(if-let [result (pred arg)]
(update errors :errors conj (handle-error result))
errors))
errors
checks))
(prn
(validate
[[even? (constantly "must not be even")]
[odd? (constantly "must not be odd")]
[zero? (constantly "must not be zero")]
[pos? (constantly "must not be positive")]]
{:errors []}
42))
; → {:errors ["must not be even" "must not be positive"]}
我有几个 Clojure 谓词,它们根据不同的业务规则验证应用程序输入。考虑到这一点,我想知道遍历这一系列谓词的最佳策略是什么:
- 我不想使用例外,因为违规是预期的。
->some
将不起作用,因为它只会出现第一个nil
。而我需要将所有的违规推送到一个违规集合中。
我考虑过以下方法,但我对此表示怀疑。
(defn validate [arg]
(cond
(logic/check-one? arg) (add-violation-one)
(logic/check-two? arg) (add-violation-two)))
一种方法是使用 cond->
。它运行所有检查并且它
向下传递分支的结果。例如
(let [arg 42
add-error #(update %1 :errors conj %2)]
(cond-> {:errors []}
(even? arg) (add-error "must not be even")
(odd? arg) (add-error "must not be odd")
(zero? arg) (add-error "must not be zero")
(pos? arg) (add-error "must not be positive")))
; → {:errors ["must not be even" "must not be positive"]}
这种方法最有意义,如果你真的想写出那些 手工的东西。不直接依赖可能更灵活 来自核心的东西并编写你自己的功能。例如。你可以减少 在谓词和错误处理程序的元组上。
(defn validate
[checks errors arg]
(reduce
(fn validation-step [errors [pred handle-error]]
(if-let [result (pred arg)]
(update errors :errors conj (handle-error result))
errors))
errors
checks))
(prn
(validate
[[even? (constantly "must not be even")]
[odd? (constantly "must not be odd")]
[zero? (constantly "must not be zero")]
[pos? (constantly "must not be positive")]]
{:errors []}
42))
; → {:errors ["must not be even" "must not be positive"]}