Clojure 带有可选参数的DSL语法
我正在尝试处理以下DSL:Clojure 带有可选参数的DSL语法,clojure,dsl,Clojure,Dsl,我正在尝试处理以下DSL: (simple-query (is :category "car/audi/80") (is :price 15000)) 这非常顺利,所以我又添加了一件事——传递给查询的选项: (simple-query {:page 1 :limit 100} (is :category "car/audi/80") (is :price 15000)) 现在我有一个问题,如何以最文明的方式处理这个案件。正如您所看到的,simple query可能将hash
(simple-query
(is :category "car/audi/80")
(is :price 15000))
这非常顺利,所以我又添加了一件事——传递给查询的选项:
(simple-query {:page 1 :limit 100}
(is :category "car/audi/80")
(is :price 15000))
现在我有一个问题,如何以最文明的方式处理这个案件。正如您所看到的,simple query
可能将hash-map作为第一个元素(后面是一长串条件)获取,或者可能根本没有hash-map选项。此外,我希望将默认设置作为一组默认选项,以防在查询中某些(或全部)选项未明确提供
这就是我想出来的:
(def ^{:dynamic true} *defaults* {:page 1
:limit 50})
(defn simple-query [& body]
(let [opts (first body)
[params criteria] (if (map? opts)
[(merge *defaults* opts) (rest body)]
[*defaults* body])]
(execute-query params criteria)))
我觉得有点乱。你知道如何简化这个结构吗?为了在我自己的代码中解决这个问题,我有一个方便的函数,我想让你见见<编码>在时拍摄
user> (defn take-when [pred [x & more :as fail]]
(if (pred x) [x more] [nil fail]))
#'user/take-when
user> (take-when map? [{:foo :bar} 1 2 3])
[{:foo :bar} (1 2 3)]
user> (take-when map? [1 2 3])
[nil [1 2 3]]
所以我们可以使用它为可选的map-first参数实现一个解析器
user> (defn maybe-first-map [& args]
(let [defaults {:foo :bar}
[maybe-map args] (take-when map? args)
options (merge defaults maybe-map)]
... ;; do work
))
因此,就我而言,您提出的解决方案或多或少是正确的,我将通过分解用于获取选项映射的解析器(这里是我的take when
helper)和分解将默认值合并到它自己的绑定语句来清理它
一般来说,使用动态变量存储配置是一种反模式,这是因为在惰性评估时可能会出现错误行为。这样的情况怎么样
(defn simple-query
[& body]
(if (map? (first body))
(execute-query (merge *defaults* (first body)) (rest body))
(execute-query *defaults* body)))
是的,现在看起来好多了。我不知道你描述的反模式。有没有其他方法可以在函数之间共享此类默认值以避免重复它们?如果您想共享“默认”值,那么我建议在某个地方定义默认配置。常见的用例通常是客户端采用默认配置并自行更新。有关使用动态变量进行配置的危险性的更多信息,请参阅。@MichalI不确定我在想什么,您不需要递归调用-请参阅我的编辑。