=========
Library provides composable algorithmic transformations that are independent from the context of their input and output sources and specify only the essence of the transformation. In other words transducers are not coupled with a data they are operating & there for can operate on built-in JS types like arrays, strings, numbers, iterators as well as they could on custom types like Immutable.js data structures, RxJS Observables, CSP Channels or whatever else you may decide to use them for.
Following resources provide an excelent introduction to Transducers idea that this this library imlements.
Applies f
onto each item of the input data structure.
const {map} = require("transducers")
const inc = map(x => x + 1)
inc([2, 3, 4]) // => [3, 4, 5]
Keeps only items from input on which p(item)
returned logical true
.
const {filter} = require("transducers")
const isEven = x => !(x % 2)
filter(isEven)([1, 2, 3, 4]) // => [2, 4]
Removes items from input on with p(item)
returned logical true
.
const {remove} = require("transducers")
const isEven = x => !(x % 2)
remove(isEven)([1, 2, 3, 4]) // => [1, 3]
Drops first n
number of items from the input.
const {drop} = require("transducers")
drop(2)([1, 2, 3, 4]) // => [3, 4]
Drops items from the input while p(item)
is logical true
. Note that once
p(item)
returns logical false
p
is no longer applied to items.
const {dropWhile} = require("transdures")
dropWhile(x => x < 5)([1, 3, 7, 4, 9]) // => [7, 4, 9]
Drops duplicate items form the input (equality compared with ===).
const {dropRepeats} = require("transducers")
dropRepeats([1, 2, 2, 2, 3, 3, 4]) // => [1, 2, 3, 4]
Takes first n
number of items from the input.
const {take} = require("transducers")
take(3)([1, 2, 3, 4, 5]) // => [1, 2, 3]
Takes items as long as p(item)
returns logical true
. Note than once
p(item)
returns logical false
p
is no longer applied to items.
const {takeWhile} = require("transducers")
takeWhile(x => x < 5)([1, 4, 6, 5, 3]) // => [1, 4]
Collects inputs into arrays of size n
. In case there are not enough padding
items, last partition will have less than n
items.
const {partition} = require("transducers")
partition(3)([0, 1, 2, 3, 4, 5]) // => [[0, 1, 2], [3, 4, 5]]
partition(3)([0, 1, 2, 3]) // => [[0, 1, 2], [3]]
Concatenates items of the input. Assumes that items are collections.
const {cat} = require("transducers")
cat([[1, 2, 3], [4], [5, 6]]) // => [1, 2, 3, 4, 5, 6]
If map
is passed a transducer produces composed transducer:
(filter(isEven))
(map(inc))
([1, 4, 9, 10]) // => [5, 11]
In fact library does not expose mapcat
as it's pretty much made obsolete
by a composition API.
map(x => x.split("/"))(cat)(["path/to", "dir/file"]) // => ["path", "to", "dir", "file"]
There are other two known implementations of [Transducers][] in JS:
In fact this library initially started as an attempt to enhance API of transducers.js and of a general idea, which also lead it to it's own path.
The core difference from both of the libraries is in the way transducers are composed & applied to input. In that regard it actually has more in common with fab.js than transducers.
In above mentioned libraries transducer application happens through other functions like into, reduce & transduce & expectation is that data type constructors can take transducer to create transduced version of it. In contrast this library does not provide into and considers both reduce and transduce to be to low level APIs. For most common cases you would want to transform a data structure of a type to different data structure of the same type. In this library transducer functions can just take that data structure as an argument and return transformed version:
const inc = x => x + 1
map(inc)([1, 2, 3]) // => [2, 3, 4]
map(char => char.toUpperCase())("hello") // => "HELLO"
In this library transdures can also apply to primitives values like numbers just as well as they can to collections:
map(inc)(5) // => 6
any transformation over nil types like null
and undefined
is no op and
return input back:
map(inc)(null) // => null
map(_ => 5)(null) // => null
Transducers in all of the libraries (including this one) can be composed with
as a plain function composition that you know or at least have seen in [underscore.js][http://underscorejs.org/#compose].
Idea is simple composing f()
and g()
functions produces f(g())
.
reduce(_.compose(x => x + 1, x => x * 2), 0, 2) // => 5
Although in case of transducers there is a surprising twist related to the implementation illustrated in the example below:
reduce(_.compose(map(x => x + 1), map(x => x * 2), [], [2]) // => [6]
Unlike right to left execution as in ordinary function composition execution order in transducers is from left to right instead. In order to avoid confusion & dependency on additional composition constructs this library takes inspiration from an API pioneered by fab.js a while back:
(map(x => x + 1))
(map(x => x * 2))
([2, 3]) // => [6, 8]
Execution is from top to bottom & no extra functions are need to compose them.
P.S.: You still could use _.compose
but in that case avoid using application like
_compose(f, g)([1, 2, 3])
as that won't do what you expect, given that input will be
passed to g
and then result to f
instead of passing it to f.g
composition.