Ramda' transduce
启用了creation of lazy sequences。
R.chain
可以在传感器中用作一对多运算符,如此(REPL):
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)
不会是懒惰的 - 所有等级都会被映射(创建中间数组),然后只有链才会“管道”#39;它们一个接一个地按照换能器顺序。
这不是问题,除非您要映射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
会阻止任何懒惰的评估。
有没有办法创建一个懒惰的一对多传感器分支?
请注意,R.reduce支持iterables。
另外,请参阅related github issue,其中提供了解决方案,但未使用ramda - 这就是我之后的事。
答案 0 :(得分:3)
您遇到的问题是,只要遇到R.map(concat(suit),ranks)
,就会立即全额评估。这与你提到的_makeFlat
函数无关,因为当使用传感器时_dispatchable
实际上不会在R.chain
的定义内调用函数体,而是使用传感器定义在_xchain
内。
因此,我们不是只生成一个完整的映射列表,而是创建一个我将调用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>
&#13;