-
Notifications
You must be signed in to change notification settings - Fork 7
/
applicable.ts
125 lines (119 loc) · 3.32 KB
/
applicable.ts
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
121
122
123
124
125
/**
* Applicable is a structure that allows a function to be applied inside of the
* associated concrete structure. For example, `Option` may hold a value of
* `(a: A) => B` inside of it. An Applicable for Option would allow one to
* apply the `A` in an `Option<A>` to the function `(a: A) => B` in an
* `Option<(a: A) => B>`, resulting in an `Option<B>`.
*
* @module Applicable
* @since 2.0.0
*/
import type { $, Hold, Kind } from "./kind.ts";
import type { Combinable } from "./combinable.ts";
import type { Mappable } from "./mappable.ts";
import type { Wrappable } from "./wrappable.ts";
/**
* The Applicable interface. This interface includes the methods apply, map, and
* wrap.
*
* @since 2.0.0
*/
export interface Applicable<
U extends Kind,
> extends Mappable<U>, Wrappable<U>, Hold<U> {
readonly apply: <
A,
B = never,
C = never,
D = unknown,
E = unknown,
>(
ta: $<U, [A, B, C], [D], [E]>,
) => <
I,
J = never,
K = never,
L = unknown,
>(
tfai: $<U, [(value: A) => I, J, K], [L], [E]>,
) => $<U, [I, B | J, C | K], [D & L], [E]>;
}
/**
* @since 2.0.0
*/
export function getApplicableCombinable<U extends Kind>(
{ apply, map }: Applicable<U>,
): <A, B = never, C = never, D = unknown, E = unknown>(
combinable: Combinable<A>,
) => Combinable<$<U, [A, B, C], [D], [E]>> {
return <A, B = never, C = never, D = unknown, E = unknown>(
{ combine }: Combinable<A>,
): Combinable<$<U, [A, B, C], [D], [E]>> => {
const _map = map(combine);
return {
combine: (second) => (first) => apply(first)(_map(second)),
};
};
}
/**
* Compose two Applicables into a new apply function.
*
* @since 2.0.0
*/
export function apply<U extends Kind, V extends Kind>(
U: Applicable<U>,
V: Applicable<V>,
): <
A,
B = never,
C = never,
D = unknown,
E = unknown,
J = never,
K = never,
L = unknown,
M = unknown,
>(
uva: $<U, [$<V, [A, B, C], [D], [E]>, J, K], [L], [M]>,
) => <I>(
uvfai: $<U, [$<V, [(a: A) => I, B, C], [D], [E]>, J, K], [L], [M]>,
) => $<U, [$<V, [I, B, C], [D], [E]>, J, K], [L], [M]> {
// deno-lint-ignore no-explicit-any
return ((uva: any) => (uvfai: any) => {
return U.apply(uva)(
U.map(
// deno-lint-ignore no-explicit-any
(vfai: any) => (va: any) => V.apply(va)(vfai),
)(uvfai),
);
// deno-lint-ignore no-explicit-any
}) as any;
}
/**
* @since 2.0.0
*/
export function applyFirst<U extends Kind>(
U: Applicable<U>,
): <I, B = never, C = never, D = unknown, E = unknown>(
second: $<U, [I, B, C], [D], [E]>,
) => <A>(first: $<U, [A, B, C], [D], [E]>) => $<U, [A, B, C], [D], [E]> {
return <I, B = never, C = never, D = unknown, E = unknown>(
second: $<U, [I, B, C], [D], [E]>,
) =>
<A>(first: $<U, [A, B, C], [D], [E]>): $<U, [A, B, C], [D], [E]> =>
U.apply(second)(U.map((a: A) => (_: I) => a)(first));
}
/**
* @since 2.0.0
*/
export function applySecond<U extends Kind>(
U: Applicable<U>,
): <I, B = never, C = never, D = unknown, E = unknown>(
second: $<U, [I, B, C], [D], [E]>,
) => <A>(first: $<U, [A, B, C], [D], [E]>) => $<U, [I, B, C], [D], [E]> {
return <I, B = never, C = never, D = unknown, E = unknown>(
second: $<U, [I, B, C], [D], [E]>,
) =>
<A>(first: $<U, [A, B, C], [D], [E]>): $<U, [I, B, C], [D], [E]> =>
U.apply(second)(U.map(() => (i: I) => i)(first));
}