SQL提供了一个名为coalesce(a, b, c, ...)
的函数,如果它的所有参数都为null,则返回null,否则返回第一个非null参数。
你会如何在Clojure中写这样的东西?
将按以下方式调用:(coalesce f1 f2 f3 ...)
其中fi
为表单,只应在需要时进行评估。如果f1
为非零,则不应评估f2
- 它可能会产生副作用。
也许Clojure已经提供了这样的功能(或宏)。
编辑:这是我提出的解决方案(修改自Stuart Halloway的编程Clojure,(and ...)
宏(第206页):
(defmacro coalesce
([] nil)
([x] x)
([x & rest] `(let [c# ~x] (if c# c# (coalesce ~@rest)))))
似乎工作。
(defmacro coalesce
([] nil)
([x] x)
([x & rest] `(let [c# ~x] (if (not (nil? c#)) c# (coalesce ~@rest)))))
固定。
答案 0 :(得分:22)
你想要的是“或”宏。
从左到右逐个评估exprs。如果是表格 返回逻辑真值,或返回该值而不返回 评估任何其他表达式,否则返回 最后一个表达式的值。 (或)返回nil。
http://clojuredocs.org/clojure_core/clojure.core/or
如果您只想要nil而不是false,请重写并命名为coalesce。
编辑:
这不能作为函数完成,因为函数首先评估所有参数。这可以在Haskell中完成,因为函数是懒惰的(不是100%肯定Haskell的事情)。
答案 1 :(得分:4)
基于nickik的回答和“或”clojure宏:
(defmacro coalesce
([] nil)
([x] x)
([x & next]
`(let [v# ~x]
(if (not (nil? v#)) v# (coalesce ~@next)))))
答案 2 :(得分:3)
您可以使用1.2中引入的保持:
编辑:扩展答案一点点。直接调用的宏。助手,例如。 apply + lazy seq产生值。(defn coalesce*
[values]
(first (keep identity values)))
(defmacro coalesce
[& values]
`(coalesce* (lazy-list ~@values)))
然而,为了防止对价值进行评估,人们需要一些本土的方式。
丑:
(lazy-cat [e1] [e2] [e3])
代码中涉及的更多但更漂亮:
(defn lazy-list*
[& delayed-values]
(when-let [delayed-values (seq delayed-values)]
(reify
clojure.lang.ISeq
(first [this] @(first delayed-values))
(next [this] (lazy-list* (next delayed-values)))
(more [this] (or (next this) ())))))
(defmacro lazy-list
[& values]
`(lazy-list* ~@(map (fn [v] `(delay ~v)) values))
答案 3 :(得分:2)
coalesce的某些函数版本,如果您更愿意避免使用宏:
(defn coalesce
"Returns first non-nil argument."
[& args]
(first (keep identity args)))
(defn coalesce-with
"Returns first argument which passes f."
[f & args]
(first (filter f args)))
用法:
=> (coalesce nil "a" "b")
"a"
=> (coalesce-with not-empty nil "" "123")
"123"
与规范不同,这将评估所有args。如果您想进行短路评估,请使用or
或其他适当的宏解决方案。
答案 4 :(得分:0)
也许我误解了这个问题,但这不仅仅是第一个过滤后的元素吗?
E.g:
user=> (first (filter (complement nil?) [nil false :foo])) false user=> (first (filter (complement nil?) [nil :foo])) :foo user=> (first (filter (complement nil?) [])) nil user=> (first (filter (complement nil?) nil)) nil
可以缩短为:
(defn coalesce [& vals] (first (filter (complement nil?) vals)))
user=> (coalesce nil false :foo) false user=> (coalesce nil :foo) :foo user=> (coalesce nil) nil user=> (coalesce) nil