考虑这段相当嵌套的 clojure 代码,它描述了传递给命令行工具的 edn-config 文件的验证过程。
(defn -main [& [config-path]]
(if config-path
(if-let [content (read-file config-path)]
(if-let [raw-data (read-edn content)]
(if-let [parsed (parse raw-data)]
(start-processing parsed)
(error "parsing-error"))
(error "invalid-edn-format"))
(error "file-not-found"))
(error "no argument"))
注意:调用的函数是虚拟函数
这需要更少嵌套和更少命令的方式来做到这一点。您对这里有什么改进建议吗?
上面的函数实际上可以归结为4个验证函数,它们是链式调用的:(1) Argument-Check,(2) File-Read,(3) Parse-EDN,(4) Parse-Data 。它们处理“错误”的方式有所不同:对于 1 和 4,我使用 clojure.spec,因此 :clojure.spec/invalid 在失败时返回。当出现问题时,其他的(2 和 3)会抛出异常。 这使得这里的抽象变得特别困难。
最佳答案
使用任一
monad。
首先,您需要修改函数以返回Either
:
(require '[cats.monad.either :as either])
(defn assert-config-path-e [config-path]
(if config-path
(either/right config-path)
(either/left "no argument")))
(defn read-file-e [config-path]
;; interpret return value as error
(if-let [content (read-file config-path)]
(either/right content)
(either/left "file-not-found")))
(defn read-edn-e [content]
(try
(read-edn content)
(catch ...
;; interpret thrown exception as error
(either/left "invalid-edn-format"))))
(defn parse-e [raw-data]
(if-let [parsed (parse raw-data)]
(either/right parsed)
(either/left "parsing-error")))
Right
值表示计算成功,Left
- 发生了错误。
之后使用do
-notation/mlet
组合所有内容:
(require '[cats.core :as cats])
(defn -main [& [config-path]]
(cats/mlet [_ (assert-config-path-e config-path)
content (read-file-e config-path)
raw-data (read-edn-e content)
parsed (parse-e raw-data)]
(cats/return (start-processing parsed)))
关于clojure - cli-tool : Avoiding nested if's 配置文件的验证过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39206491/