Clojure凝聚函数
SQL提供了一个名为Clojure凝聚函数,clojure,coalesce,Clojure,Coalesce,SQL提供了一个名为coalesce(a,b,c,…)的函数,如果其所有参数都为null,则返回null,否则返回第一个非null参数 你会如何在Clojure写这样的东西 它的名称如下:(合并f1 f2 f3…,其中fi是形式,只有在需要时才应进行评估。如果f1为非零,则不应评估f2——它可能有副作用 也许Clojure已经提供了这样一个函数(或宏) 编辑:这里是我提出的一个解决方案(修改自Stuart Halloway的编程Clojure,(和…宏,第206页): 似乎有效 (defmacr
coalesce(a,b,c,…)
的函数,如果其所有参数都为null,则返回null,否则返回第一个非null参数
你会如何在Clojure写这样的东西
它的名称如下:(合并f1 f2 f3…
,其中fi
是形式,只有在需要时才应进行评估。如果f1
为非零,则不应评估f2
——它可能有副作用
也许Clojure已经提供了这样一个函数(或宏)
编辑:这里是我提出的一个解决方案(修改自Stuart Halloway的编程Clojure,(和…
宏,第206页):
似乎有效
(defmacro coalesce
([] nil)
([x] x)
([x & rest] `(let [c# ~x] (if (not (nil? c#)) c# (coalesce ~@rest)))))
已修复。您需要的是“或”宏
从左到右一次计算一个表达式。如果是表格
返回逻辑真值,或返回该值而不返回
对任何其他表达式求值,否则返回
最后一个表达式的值。(或)返回零
如果您只想要nil而不是false,请重写and并将其命名为coalesce
编辑:
这不能作为函数来完成,因为函数首先计算其所有参数。这可以在Haskell中完成,因为函数是惰性的(对Haskell的事情不是100%确定)。您可以使用1.2中介绍的keep: 编辑:稍微扩展一下答案。用于直接调用的宏。例如,apply+lazy seq的助手生成值
(defn coalesce*
[values]
(first (keep identity values)))
(defmacro coalesce
[& values]
`(coalesce* (lazy-list ~@values)))
然而,为了防止对价值观的评估,我们需要一些本土的方法
丑陋的:
代码中有一点更复杂但更漂亮:
(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))
根据nickik的回答和“或”clojure宏:
(defmacro coalesce
([] nil)
([x] x)
([x & next]
`(let [v# ~x]
(if (not (nil? v#)) v# (coalesce ~@next)))))
也许我误解了这个问题,但这不是第一个过滤元素吗 例如: user=>(第一个(过滤器(补码nil?[nil false:foo])) 假的 user=>(第一个(过滤器(补码nil?[nil:foo])) :foo 用户=>(第一个(过滤器(补零?[])) 无 用户=>(第一个(过滤器(补码为零?)为零) 无 可缩短至: (defn coalesce [& vals] (first (filter (complement nil?) vals))) (defn合并[&VAL] (第一个(过滤器(补码为零?)VAL))) user=>(合并为nil false:foo) 假的 用户=>(合并零:foo) :foo 用户=>(合并为零) 无 用户=>(合并) 无
如果您希望避免使用宏,请选择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"
与规范不同,这将评估所有参数。如果需要短路评估,请使用
或或其他适当的宏解决方案。我需要第一个非零值,而不是最后一个,但是(或…
满足我的需要。我没有意识到(and…
和(or…
返回值。我认为他们的回答是假是真。但是即使是这些也不会返回我想要的输入值false
。哦,我肯定会更改它。@user128186:不确定您是否需要(not(nil?v#))
(if…
语句中的)
,因为任何不是false
或nil
的值都会计算为true
。否则,我们的解决方案是相同的。你为什么要对“or”-宏进行1:1重写?@Ralph:那么你希望first不是nil或first不是false值?@ajan:很好!我想我需要显式地测试nil
。@nickik::-)没有意识到我有。我知道为什么非宏解决方案可能更好,因为宏解决方案不能与其他函数组合。@ralph:当然,接受的解决方案更快,但我的解决方案更灵活。你应该选择什么取决于你的需要。如果您不需要速度,但有一个懒洋洋创建的序列要合并,那么我的解决方案就是这样。如果您需要快速处理少数已知值。然后是阿扬的救援方案。YMMV.)我不是在批评。不管怎么说,这更像是一项学术活动。我在考虑如何在Scala中实现“elvis”操作符,这让我想到了Clojure中类似的东西。这是另一种seq-y方法。第三个是(第一个(删除nil?…)
。但是,这并不能解决要合并的表达式只能根据需要进行计算的问题。对于像(重复地#(生成某个东西))
这样的东西,这在盒子的底部有效,但对于“文字”值无效:[(做某件事)(做其他事)(做第三件事)]
。在这里,所有的东西都是在过滤器看到之前进行评估的。是的,我错过了args需求的延迟评估。
(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
(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"