| 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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 | 3x
3x
3x
6x
4x
2x
6x
5x
4x
4x
3x
2x
16x
4x
16x
4x
3x
1x
3x
3x
3x
3x
2x
1x
1x
4x
3x
3x
3x
3x
4x
4x
4x
3x
2x
2x
2x
1x
1x
2x
1x
1x
3x
2x
1x
1x
9x
8x
5x
3x
3x
4x
| import { truthy, existy } from './predicates';
import { construct, cat } from './collections';
import { fail } from './util';
export function doWhen(cond, action) {
if (truthy(cond))
return action();
else
return undefined;
}
export function invoker(name, method) {
return (target, ...args) => {
if (!existy(target)) fail("Must provide a target");
const targetMethod = target[name];
return doWhen((existy(targetMethod) && method === targetMethod), () => {
return targetMethod.apply(target, args);
});
}
}
// fnull takes a function as an arg and a number of additional args and returns
// a function that just calls the original function given. If null/undefined
// are present it will replace them with some defaults:
//
// so lets say the fun passed in was (x, y) => x * y if we want to provide a
// default for x, y at any point it gets called we can add in two defaults for
// example: fnull(multiply, 1, 1); Now 1 will be replaced with x or y if they're
// ever undefined or null.
export function fnull(fun, ...defaults) {
return function(...secondArgs) {
const args = secondArgs.map((e, i) => {
return existy(e) ? e : defaults[i];
});
return fun.apply(null, args);
}
}
// Creates a predicate function to be used with 'checker' that conforms to its
// expected API of having a 'message' field.
export function validator(msg, fun) {
const f = function(...args) {
return fun.apply(fun, args);
}
f.message = msg;
return f;
}
// checker can be used to do validation
export function checker(...validators) {
return obj => {
return validators.reduce((errs, check) => {
Iif (check(obj)) {
return errs;
} else {
return [...errs, check.message];
}
}, []);
}
}
// The contract of dispatch: it will keep trying to execute functions until it
// runs out or one returns an existy value.
export function dispatch(...funs) {
const size = funs.length;
return (target, ...args) => {
let ret = undefined;
for (let funIndex = 0; funIndex < size; funIndex++) {
const fun = funs[funIndex];
ret = fun.apply(fun, [target, ...args]);
if (existy(ret)) return ret;
}
return ret;
}
}
// Currying
export function curry(fun) { return arg => fun(arg); }
export function curry2(fun) {
return secondArg => firstArg => fun(firstArg, secondArg);
}
export function curry3(fun) {
return last => middle => first => fun(first, middle, last);
}
// Partial Application
export function partial1(fun, arg1) {
return (...pargs) => {
const args = construct(arg1, pargs)
return fun.apply(fun, args)
}
}
export function partial2(fun, arg1, arg2) {
return (...pargs) => {
const args = cat([arg1, arg2], pargs);
return fun.apply(fun, args);
}
}
export function partial(fun, ...pargs) {
return (...internalArgs) => {
const args = cat(pargs, internalArgs);
return fun.apply(fun, args);
}
}
export function compose(...funcs) {
if (funcs.length === 0) return arg => arg
if (funcs.length === 1) return funcs[0]
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
|