代码之家  ›  专栏  ›  技术社区  ›  Ralph java.is.for.desktop

Clojure合并函数

  •  13
  • Ralph java.is.for.desktop  · 技术社区  · 14 年前

    coalesce(a, b, c, ...) 如果其所有参数都为空,则返回空,否则返回第一个非空参数。

    你怎么能在Clojure写这样的东西?

    它将被称为: (coalesce f1 f2 f3 ...) fi 是形式 只有在需要的时候才应该评估 . 如果 f1 是非零的,那么 f2 不应该被评估——它可能有副作用。

    编辑 :这里是我提出的一个解决方案(修改自Stuart Halloway的编程Clojure, (and ...)

    (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)))))
    

    5 回复  |  直到 14 年前
        1
  •  4
  •   Arjan    14 年前

    基于nickik的回答和“或”clojure宏:

    (defmacro coalesce
        ([] nil)
        ([x] x)
        ([x & next]
           `(let [v# ~x]
               (if (not (nil? v#)) v# (coalesce ~@next)))))
    
        2
  •  24
  •   Drew Noakes    10 年前

    你想要的是“或”宏。

    从左到右逐个计算表达式。如果一个表格 对任何其他表达式求值,否则返回

    http://clojuredocs.org/clojure_core/clojure.core/or

    如果你只想要nil而不是false,请重写并将其命名为coalesce。

    编辑:

    这不能作为函数执行,因为函数首先计算其所有参数。这可以在Haskell中完成,因为函数是惰性的(不能百分之百确定Haskell的事情)。

        3
  •  3
  •   kotarak    14 年前

    您可以使用1.2中的keep Introducted:

    (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))
    
        4
  •  2
  •   Brad Koch Daniel Wright    9 年前

    如果希望避免使用宏,可以使用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"
    

    与规范不同,这将计算所有参数。使用 or 或另一个适当的宏解决方案,如果你想短路评估。

        5
  •  0
  •   Alex Taggart    14 年前

    也许我误解了这个问题,但这不只是第一个过滤元素吗?

    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