関連する質問があるか否かに関して生じ、彼らはそれを他の要素から各 入力変換は、その入力独立 の各要素に適用されることが、想定
それらはtransducers命名されています彼らは(暗黙の)状態を持つかもしれないからです。
トランスデューサは、リダクション関数を取り、リダクション関数を返す関数です。
還元関数は、アキュムレータとアイテムの2つのパラメータを必要とし、更新されたアキュムレータを返す関数です。
これは、変更可能な状態(存在する場合)を保持する還元関数です。
トランスデューサを取得するには、合成時間と計算時間の2回で動作することを理解する必要があります。そのため、関数を返す関数です。
簡単な還元関数から始めましょう:conj
。
(map inc)
によって返された変換器は(fn [rf] (fn [acc x] (rf acc (inc x))))
です。 conj
で呼び出すと、(fn [acc x] (conj acc (inc x)))
に相当する関数が返されます。
(filter odd?)
が返す変換器は(fn [rf] (fn [acc x] (if (odd? x) (rf acc x) acc)))
です。 conj
で呼び出すと、(fn [acc x] (if (odd? x) (conj acc x) acc)))
に相当する関数が返されます。これは、(下流の還元機能が短絡することがあるため)という興味深いものです。
あなたはこれらの2つの変換器チェーンにしたい場合は、あなただけの(comp (map inc) (filter odd?))
あなたがこの複合トランスデューサにconj
を渡すならば(comp
は右から左への機能を適用するため)、(filter odd?)
はconj
をラップする最初になるだろう。次いで、得られたfiltered-rf
機能に機能equiavlentをもたらす(map inc)
に渡される:filtered-rf
が(fn [acc x] (if (odd? x) (conj acc x) acc)))
ある
(fn [acc x] (filtered-rf acc (inc x)))
。 filtered-rf
の場合は、(fn [acc x] (let [x+1 (inc x)] (if (odd? x+1) (conj acc x+1) acc)))
となります。
ご覧のとおり、中間のコレクションやシーケンスは割り当てられていません。
還元機能が可変状態(可能な限り少ない)で、以前の項目をすべて保持しないという点を除いて同じ話です。通常は揮発性のボックス(volatile!
参照)または変更可能なJavaオブジェクトです。
例題の項目が最初にマッピングされ、次にフィルタリングされていることに気づいたかもしれません。計算は左から右に適用され、comp
と矛盾しているようです。これはそうではありません:comp
はトランスデューサを構成しています。fnsを減らしてfnをラップします。したがって、合成時間にラッピングが右から左に行われます(conj
は "rf"をフィルタリングし、その後 "mapping rf"でラップします)が、計算時にラッピングレイヤは内側にトラバースされます:map、filter、conj。
独自のトランスデューサ(reduced
、初期化および完了アライメント)の実装には細かい実装の詳細がありますが、一般的な考えは上記のものです。