2017-12-12 6 views
1

RAMDA怠惰

RAMDAのtransduceためにはcreation of lazy sequencesができます。RAMDAのトランスデューサ:レイジー1対多のブランチ

多く

R.chainの一つはそれほど(REPL)のように、1対多数の演算子として、変換器に使用することができる。

const tapLog = R.tap((what) => console.log(what)) 

const suits = ['♠', '♥', '♦', '♣'] 
const ranks = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'J', 'Q', 'K', 'A'] 

const addRank = (suit) => R.map(concat(suit),ranks) 

var transducer = R.compose(
R.chain(addRank), 
tapLog, 
R.take(2) 
); 

R.into([], transducer, suits); 

// => ♠1 // console.log 
// => ♠2 // console.log 
// => ["♠1", "♠2"] 

問題

問題と上のスニペットはR.map(concat(suit),ranks)が怠惰ではないということです - すべてのランクがマッピングされ(中間配列を作成する)、チェーンだけがトランスデューサシーケンスを1つずつパイプします。

680kグラフノードをマッピングしない限り、これは問題ではありません。

なぜこのようなことが起こりますか?

R.chainの実装はそうのようになります。

var chain = _curry2(_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { 
if (typeof monad === 'function') { 
    return function(x) { return fn(monad(x))(x); }; 
} 
return _makeFlat(false)(map(fn, monad)); 
})); 

そして、それはそのブロック_makeFlat任意の遅延評価です。

目標

は怠惰な1対多のトランスデューサ・ブランチを作成する方法はありますか?

R.reduceはiterablesをサポートしています。

また、ソリューションが提供されていますが、ramdaを使用していないrelated github issueを参照してください。これは私の後ろです。

答えて

2

あなたが遭遇した問題は、R.map(concat(suit),ranks)が発生すると直ちに評価され、完全に評価されることです。これは、変換器を使用するときのように、R.chainの定義内で実際に関数本体を呼び出すのではなく、_xchainの変換器定義を使用するので、言及した_makeFlat関数とは無関係です。

したがって、マップされたリスト全体を生成するのではなく、新しいトランスデューサを作成してcombineWithと呼びます。例ではconcatのような機能を持ち、各要素を組み合わせて変換。道に沿って@@transducer/reducedをチェックしながらそれを行うことができます。

const combineWith = (fn, xs) => xf => ({ 
 
    // proxy both `init` and `result` straight through 
 
    // see internal/_xfBase.js 
 
    '@@transducer/init': xf['@@transducer/init'].bind(xf), 
 
    '@@transducer/result': xf['@@transducer/result'].bind(xf), 
 

 
    // combine the item at each step with every element from `xs` 
 
    // using `fn`, returning early if `reduced` is ever encountered 
 
    '@@transducer/step': (acc, item) => { 
 
    for (const x of xs) { 
 
     acc = xf['@@transducer/step'](acc, fn(item, x)) 
 
     if (acc['@@transducer/reduced']) return acc 
 
    } 
 
    return acc 
 
    } 
 
}) 
 

 
const suits = ['♠', '♥', '♦', '♣'] 
 
const ranks = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'J', 'Q', 'K', 'A'] 
 

 
const tapLog = R.tap(console.log.bind(console, 'tapLog')) 
 

 
const transducer = R.compose(
 
    combineWith(R.concat, ranks), 
 
    tapLog, 
 
    R.take(2) 
 
) 
 

 
console.log('result', R.into([], transducer, suits))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

+0

だから、血まみれのシンプル!あなたは私の質問に答えただけでなく、「R.transduce」の文書全体を完全に解読しています。どのようなことが推測されているのでしょうか?[答えはそこにすべてありました](https://github.com/ramda/ramda/blob/f494250c0aed9ecc096cc5b5b7823661edc14de2/source/internal/_xtap.js)、それは私を騙したすべてのノイズです!私はあなたの答えを少し修正してinit/resultを詳しく説明しました。 – Izhaki

関連する問題