Ramda for the lazy
Ramda's transduce
enables the creation of lazy sequences.
One to many
R.chain
can be used in a transducer as a one-to-many operator, like so (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"]
The issue
The issue with the snippet above is that R.map(concat(suit),ranks)
will not be lazy - all the ranks will be mapped (creating intermediate array), and only then chain will 'pipe' them one by one down the transducer sequence.
This is not an issue, unless you are mapping 680k graph nodes.
Why is this happening?
The implementation of R.chain
looks like so:
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));
}));
And it's _makeFlat
that blocks any lazy evaluation.
The goal
Is there a way to create a lazy one-to-many transducer branch?
Note that R.reduce supports iterables.
Also, see the related github issue, where a solution is provided, but not using ramda - which is what I'm after.