transductx
A transducer library for Javascript
Description
This package offers a simple and straightforward way to perform transductions in Node.
Installation
To install the transductx
package:
$ npm install transductx
Usage
The transductx
package exports the following functions.
transduce(transformer, reducer)
The transduce()
function takes a transformer and a reducer and returns a transducer function, i.e. a reducer that
transforms its next value argument (the currentValue
argument in the MDN documentation parlance).
A transformer is any function that accepts a single argument, transforms it in some way and returns the result.
Alternatively, a transformer may act as a filter so as to omit certain values instead of transforming them. In that
case, the transformer function must be passed to predicate()
first before using it with transduce()
. See below
for more details.
The returned transducer has the same signature has a regular reducer. It can be used with transductx
' reduce()
function (see below for more details) but can also be passed to any function that can work with reducers, e.g.
Array.prototype.reduce()
.
const { predicate, transduce } = require('transductx');
const double = x => (x*2);
const increment = x => (x+1);
const iseven = x => (x%2) === 0;
const sum = (a,b) => (a+b);
let transducer = transduce( double, sum );
[1,2,3,4,5].reduce( transducer, 0 ); // returns 30
transducer = transduce( predicate(iseven), sum );
[1,2,3,4,5].reduce( transducer, 0 ); // returns 6
If the transformer argument is an iterable object (e.g. an array) instead of a function, transduce()
assumes it
is a collection of transformers and the returned transducer will apply each transformer in order. Alternatively,
you can use transform()
to compose multiple transformers to a single transformer function (see below).
const { transduce } = require('transductx');
const double = x => (x*2);
const increment = x => (x+1);
const sum = (a,b) => (a+b);
const transducer = transduce( [double, increment], sum );
[1,2,3,4,5].reduce( transducer, 0 ); // returns 35
transduce()
is a a curried function, so you can pass the arguments separately:
const { transduce } = require('transductx');
const double = x => (x*2);
const sum = (a,b) => (a+b);
const transducer = transduce(double);
[1,2,3,4,5].reduce( transducer(sum), 0 ); // returns 30
transform(...transformers)
Compose one or more transformer functions to a single function. Each transformer may be a regular transformer or a
filter transformer, i.e. a transformer that was first passed to predicate()
(see below).
const { transduce } = require('transductx');
const double = x => (x*2);
const increment = x => (x+1);
const sum = (a,b) => (a+b);
const transformer = transform( double, increment );
const transducer = transduce( transformer, sum );
[1,2,3,4,5].reduce( transducer, 0 ); // returns 35
predicate(...filters) - pass(...filters) - drop(...filters)
Return a transformer that is recognized by transduce()
as a filter transformer instead of a regular transformer, i.e.
a function that does not transform values but that tells transduce()
to either include or omit a value.
Each filter should be a function that accepts a single argument and returns a boolean to indicate whether or not its argument value should be included or omitted from the transduction.
Failing to passing a filter transformer to
predicate()
prior to transducing will causetransduce()
to produce incorrect results.predicate()
allowstransduce()
to recognize a transformer as a filter transformation rather than a regular transformation.Likewise, passing a regular transformer to
predicate()
will also causetransduce()
to produce incorrect results. So make sure to only pass filter functions topredicate()
, not regular functions.predicate()
can't tell the difference, so it will accept either.
See the sample code for transduce()
above for an example of predicate()
in action.
If more than one filter is provided, the returned transformer will filter out any value that is not accepted by all filters, i.e. it combines the filters with a logical AND operation.
const { predicate, transduce } = require('transductx');
const iseven = x => (x%2) === 0;
const isgreaterthan10 = x => (x > 10);
const islessthan20 = x => (x < 20);
const sum = (a,b) => (a+b);
// this transformer will accept only even numbers greater than 10 and less than 20
const transformer = predicate(iseven, isgreaterthan10, islessthan20);
const transducer = transduce(transformer, sum);
[8,9,10,11,12,13,14,15].reduce(transducer, 0); // returns 26
pass()
is an alias for predicate()
. drop()
is the logical opposite of predicate()
, i.e. it omits any values
for which all filters return true
.
// this transformer will accept only even numbers of 10 or less
const transformer = ( pass(iseven), drop(isgreaterthan10) );
const transducer = transduce(transformer, sum);
[8,9,10,11,12].reduce(transducer, 0); // returns 18
reduce(reducer, initialvalue, list)
The transducer returned by transduce()
has the same signature as any other reducer function, so it can be used by
any function that can reduce a collection, e.g. Array.prototype.reduce()
. The transductx
package exports a
convenience reduce()
function that accepts a reducer (any reducer function, not just transducers returned by
transduce()
), an initialvalue and a list of values to reduce.
One notable feature of reduce()
is that the list argument may be any object that has a reduce()
method or an
iterable object. If list has a reduce()
method (e.g. a Javascript Array), the reduce()
function passes reducer
and initialvalue to that method and returns the result. If list does not have a reduce()
method but it is
iterable, reduce()
will reduce the values produced by the iterable. If list has no reduce()
method and is not
iterable, an error is thrown.
const { predicate, reduce, transduce } = require('transductx');
const iseven = x => (x%2) === 0;
const isgreaterthan10 = x => (x > 10);
const islessthan20 = x => (x < 20);
const sum = (a,b) => (a+b);
// this transformer will accept only even numbers greater than 10 and less than 20
const transformer = predicate(iseven, isgreaterthan10, islessthan20);
const transducer = transduce(transformer, sum);
reduce(transducer, 0, [8,9,10,11,12,13,14,15]); // returns 26
Also, reduce()
is curried, so you can pass the arguments in separate calls.
const { predicate, reduce, transduce } = require('transductx');
const iseven = x => (x%2) === 0;
const isgreaterthan10 = x => (x > 10);
const sum = (a,b) => (a+b);
const transducer = transduce( predicate(iseven, isgreaterthan10), sum );
const sumevennumbersgreaterthan10 = reduce(transducer, 0); // curried
sumevennumbersgreaterthan10([8,9,10,11,12,13,14,15]); // returns 26
transmap(transformer, list)
This function accepts a transformer (or array of transformers) and an iterable object and returns an iterable object that transforms the values produced by the original iterable.
Normally, to be truly functional, you would create a reducer that collects its value to an array, but transmap()
returns an iterable object, not an array.
The return iterable object pulls the values from the input iterable lazily.
const { predicate, transmap } = require('transductx');
const double = x => (x*2);
const iseven = x => (x%2) === 0;
const values = transmap( [predicate(iseven), double], [1,2,3,4,5,6,7,8,9,10]);
for( const value of values ) console.log(value); // prints `4`, `8`, `12`, `16` and `20`
Typescript declarations?
Nope.