clojure - cli-tool : Avoiding nested if's 配置文件的验证过程

标签 clojure

考虑这段相当嵌套的 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/

相关文章:

clojure 行为 (into {} '(( :a :b) (:c :d)))

clojure - 在 Clojure 中比较字符串的正确方法是什么?

java - Clojure 和 JavaFX 2——将多参数传递给 JavaFX 方法

postgresql - 在 Clojure 中使用 PGobject

clojure - "Reduce and Return Intermediate Results as Sequence"的 Common Lisp 函数

clojure - 如何用更惯用的东西替换这个循环?

parsing - Clojure - 解析 Elasticsearch 查询响应并提取值

clojure - 你如何在 clojure 环形服务器中提供动态创建的文件?

clojure - clojure.set 索引函数的用法示例

带有可选标志的 Clojure 参数