Skip to content
This repository has been archived by the owner on Jun 3, 2023. It is now read-only.

Proposal: @@transducer/init should always be called, create an accumulator object. #48

Open
shaunc opened this issue Apr 25, 2017 · 0 comments

Comments

@shaunc
Copy link

shaunc commented Apr 25, 2017

CF -- jlongster/transducers.js#46 -- don't know which of these projects is more/less active.

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).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant