13

->>そのようなパイプラインを考えると:

(defn my-fn []
  (->> (get-data)
       (do-foo)
       (do-bar)
       (do-baz)))

さまざまな段階を条件付きにしたい。

頭に浮かんだこれを書く最初の方法は、そのようなものでした:

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
       (if foo (do-foo) identity)
       (if bar (do-bar) identity)
       (if baz (do-baz) identity))

ただし、->>マクロがフォームに挿入しようとするとif、パフォーマンス(noopidentity呼び出しがある)の点で不幸に見えるだけでなく、実際にはコンパイルに失敗します。

これを書くための適切で合理的に乾いた方法は何でしょうか?

4

5 に答える 5

12

最新のClojure(つまり、1.5以降)は、条件付きスレッドのさまざまなオプションをサポートしていますが、おそらく必要ですcond->>

cond->およびを使用した条件付きスレッドcond->>

Clojureはとを提供cond->cond->>、それぞれがペアのセットを要求します。テストと、そのテストがtrueと評価された場合の式です。これらは非常に似てcondいますが、最初の真のテストにとどまりません。

(cond->> 5
  true inc
  false inc
  nil inc)
=> 6

あなたの特定の例はおそらく次のように書くのが最も良いでしょう:

(defn my-fn [{:keys [foo bar baz]}]
  (cond->> (get-data)
    foo (do-foo)
    bar (do-bar)
    baz (do-baz)))

as->

as->これはおそらく最も用途の広いスレッドマクロであるため、言及する価値があります。フォームに通されている「もの」を参照するための名前が付けられます。例えば:

(as-> 0 n
  (inc n)
  (if false
    (inc n)
    n))
=> 1

(as-> 0 n
  (inc n)
  (if true
    (inc n)
    n))
=> 2

これにより、パラメーターリストのさまざまなポイントで式をスレッド化する必要がある関数の組み合わせ(つまり、->から->>構文への切り替え)を操作するときに、かなりの柔軟性が得られます。コードを読みやすくするために、無関係な名前付き変数の使用は避ける必要がありますが、多くの場合、これがプロセスを表現するための最も明確で簡単な方法です。

于 2016-01-13T12:42:08.600 に答える
11

これも機能します:

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
       (#(if foo (do-foo %) %))
       (#(if bar (do-bar %) %))
       (#(if baz (do-baz %) %)) ))
于 2012-08-01T22:46:12.380 に答える
9

これらのマクロに興味があるかもしれませんhttps://github.com/pallet/thread-expr

于 2012-08-02T02:08:16.540 に答える
5

コンパイル部分を修正できます(ただし、ifステートメントに別のセットを( )次のように配置して実行する関数を決定させることにより、禁欲的な部分ではありません。

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
   ((if foo do-foo identity))
   ((if bar do-bar identity))
   ((if baz do-baz identity)))

次のような一連の呼び出しに拡張されます。

   ;  choose function         and call it    
   ( (if foo do-foo identity) args       )
   ( (if bar do-bar identity) args       )
   ( (if baz do-baz identity) args       )
于 2012-08-01T22:39:35.730 に答える
5

この種のものが頻繁に必要な場合のより一般的な方法は次のとおりです。

(defn comp-opt [&flag-fns]
  (->>フラグ-fns
    (パーティション2)
    (最初にフィルター)
    (2番目のマップ)
    (compを適用)))

(defn my-fn [{:keys [foo bar baz]}]
  (マップ(comp-opt foo do-foo
                 バードバー
                 baz do-baz)
       (get-data)))
于 2012-08-02T00:30:57.113 に答える