13

SQLは、coalesce(a, b, c, ...)すべての引数がnullの場合はnullを返すという関数を提供します。それ以外の場合は、最初のnull以外の引数を返します。

Clojureでこのようなものをどのように書きますか?

これは次のように呼び出されます。(coalesce f1 f2 f3 ...)ここで、は必要な場合にのみ評価する必要fiがあるフォームです。がnil以外の場合は、評価しないでください。副作用が発生する可能性があります。f1f2

たぶん、Clojureはすでにそのような関数(またはマクロ)を提供しています。

編集:ここで私が思いついた解決策(StuartHallowayのプログラミング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)))))

修理済み。

4

5 に答える 5

25

必要なのは「or」マクロです。

expr を左から右に一度に 1 つずつ評価します。フォームが論理的な真の値を返す場合、またはその値を返しても他の式を評価しない場合、それ以外の場合は最後の式の値を返します。(または) nil を返します。

http://clojuredocs.org/clojure_core/clojure.core/または

false ではなく nil のみが必要な場合は、and を書き換えて、coalesce という名前を付けます。

編集:

関数はすべての引数を最初に評価するため、これを関数として行うことはできませんでした。これは、関数が遅延しているため、Haskell で実行できます (Haskell のことについて 100% 確信があるわけではありません)。

于 2010-11-03T12:22:30.583 に答える
4

nickikの回答と「または」clojureマクロに基づく:

(defmacro coalesce
    ([] nil)
    ([x] x)
    ([x & next]
       `(let [v# ~x]
           (if (not (nil? v#)) v# (coalesce ~@next)))))
于 2010-11-03T12:50:39.833 に答える
3

1.2 で導入された keep を使用できます。

編集:答えを少し拡張しました。直接呼び出し用のマクロ。例えばのためのヘルパー。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))
于 2010-11-03T12:48:16.980 に答える
0

おそらく私は質問を誤解していますが、これは最初にフィルタリングされた要素ではありませんか?

例えば:

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 合体[&vals]
  (最初の(フィルター(補数nil?)vals)))
user =>(coalesce nil false:foo)
false
user =>(coalesce nil:foo)
:foo
user =>(coalesce nil)
nil
user =>(合体)
nil
于 2010-11-04T05:38:32.013 に答える