Proposal: @@transducer/init should always be called, create an accumulator object.Β #46
Description
Consider the following implementation of a "zip" transformer:
function zip() {
return xf => Zip(xf);
}
const sub = Symbol('sub');
function Zip(xf) {
return {
['@@transducer/init']() {
const result = { [sub]: [] };
// if init is not implemented in wrapped, ignore
try {
result.wrapped = xf['@@transducer/init']();
}
catch(err) { }
return result;
},
['@@transducer/result'](result) {
if(result[sub] == null || result[sub].length === 0) {
return result.wrapped || result;
}
const wrappedResult = result[sub][0].reduce((acc, input, i)=>
xf['@@transducer/step'](acc, result[sub].map((a)=>a[i]))
, result.wrapped);
return xf['@@transducer/result'](wrappedResult);
},
['@@transducer/step'](result, input) {
if(result[sub] == null) {
// "into" - init not called
const acc = this['@@transducer/init']();
// pass the evil on to the wrapped accumulator
acc.wrapped = result;
result = acc;
}
result[sub].push(input);
return result;
}
};
}
It "works" but does it by hackery. What it should do is create an accumulator object in init
, then accumulate the subcollections. On finalization, it can feed the final objects to the downstream transformer.
I propose that @@transducer/init
be responsible to create and return an accumulator object which wraps the downstream transformer accumulator. It could have signature:
['@@transducer/init'](finalAccumulator) { }
With default implementation:
['@@transducer/init'](finalAccumulator) { return xf['@@transducer/init](finalAccumulator); }
(Here xf
is the downstream transformer -- could be this.xf
depending on implementation.)
By default, as in zip, we could use the accumulator to store state. Eg. we could have a transducer that was calculating a histogram, then forwarding the bins onwards (etc.).
If an accumulator did wrap downstream state in its own state, it is then responsible for unwrapping the downstream state in step
and result
.
finalAccumulator
is the thing into which the whole pipeline is writing. Normally we ignore it,
but special end of chain "output aware" transformers could use it (provided by the library).