2016-09-05 15 views
1

トランスジェーバーがどのようにして中間のコレクションの使用を避けているかは、(クローゼーのソースコードを除いて)すべて読んでいくことは、やや難しいです。Clojureトランスデューサはどのようにしてフード内で動作しますか?

各入力変換が入力の各要素に別個にから適用されていると仮定するかどうかに関して、トランスデューサが動作する場合に存在する可能性のある制限が発生します入力コレクションの入力変換を要素ごとに縮小します。

入力関数のコードを調べて、正しい合成結果が得られるように織り交ぜる方法を決定しますか?

クロージャーのトランスデューサはどのようにフードの下で動作しますか?

答えて

2

関連する質問があるか否かに関して生じ、彼らはそれを他の要素から各 入力変換は、その入力独立 の各要素に適用されることが、想定

それらは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、初期化および完了アライメント)の実装には細かい実装の詳細がありますが、一般的な考えは上記のものです。

関連する問題