-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
79 lines (73 loc) · 2.22 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// interface Reducer<A, B> extends Array<any> {
// /**
// * Initialization, e.g. to provide a suitable initial
// * accumulator value, only called when no initial result
// * has been provided by the user.
// */
// [0]: () => A,
// /**
// * Completion. When called usually just returns `acc`,
// * but stateful transformers should flush/apply their
// * outstanding results.
// */
// [1]: (acc: A) => A,
// /**
// * Reduction step. Combines new input with accumulator.
// * If reduction should terminate early, wrap result via
// * `reduced()`
// */
// [2]: (acc: A, x: B) => A | Reduced<A>,
// }
const sum = () => [
() => 0,
(acc) => acc,
(acc, x) => acc + x
];
const push = () => [
() => [],
(acc) => acc,
(acc, x) => (acc.push(x), acc)
];
const histogram = () => [
() => ({}),
(acc) => acc,
(acc, x) => ((acc[x] ? acc[x]++ : (acc[x]=1)), acc)
];
const reduce = (reducer, initial, xs) => {
// use reducer's default init if not user provided
let acc = initial != null ? initial : reducer[0]();
// reduce all inputs
for(let x of xs) {
acc = reducer[2](acc, x);
}
// call completion fn to post-process final result
return reducer[1](acc);
}
// then use like:
// no initial result provided, so use reducer default init
reduce(sum(), null, [1,2,3,4])
// 10
// with initial result of 100
reduce(sum(), 100, [1,2,3,4])
// 110
// reduction of a ES6 Set
reduce(sum(), 0, new Set([1,2,2,1,1,3,4,3,2]))
// 10
// strings are iterable too
console.log(reduce(histogram(), null, "reducers"))
// { r: 2, e: 2, d: 1, u: 1, c: 1, s: 1 }
// or without types
// composes transducer `xform` with reducer `rfn`
// then calls reduce
const transduce = (xform, rfn, initial, xs) =>
reduce(xform(rfn), initial, xs);
const map = (f) => (r) => [r[0], r[1], (acc, x) => r[2](acc, f(x))];
// Some basic examples, both using the same transducer, but different reducers:
// pre-build a times 10 standalone transducer for re-use
const mul10 = map((x) => x * 10)
// Replicate Array.map()
transduce(mul10, push(), null, [1, 2, 3, 4])
[ 10, 20, 30, 40 ]
// or sum up values
console.log(transduce(mul10, sum(), null, [1, 2, 3, 4]))
// 100