/
static-land.ts
119 lines (96 loc) · 3.19 KB
/
static-land.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
import { $, _ } from '.';
export interface Setoid<T> {
equals: (x: T, y: T) => boolean;
}
export interface Ord<T> extends Setoid<T> {
lte: (x: T, y: T) => boolean;
}
export interface Semigroup<T> {
concat: (x: T, y: T) => T;
}
export interface Monoid<T> extends Semigroup<T> {
empty: () => T;
}
export interface Group<T> extends Monoid<T> {
invert: (x: T) => T;
}
export interface Semigroupoid<T> {
compose: <I, J, K>(tij: $<T, [I, J]>, tjk: $<T, [J, K]>) => $<T, [I, K]>;
}
export interface Category<T> extends Semigroupoid<T> {
id: <I, J>() => $<T, [I, J]>;
}
export interface Filterable<T> {
filter: <A>(pred: (x: A) => boolean, ta: $<T, [A]>) => $<T, [A]>;
}
export interface Functor<T> {
map: <A, B>(f: (x: A) => B, t: $<T, [A]>) => $<T, [B]>;
}
export const Functor = <T>(spec: Functor<T>) => spec;
export interface Bifunctor<T> {
bimap: <A, B, C, D>(f: (x: A) => B, g: (x: C) => D, t: $<T, [A, C]>) => $<T, [B, D]>;
first: <A, B>(t: $<T, [A, B]>) => Functor<$<T, [_, B]>>;
second: <A, B>(t: $<T, [A, B]>) => Functor<$<T, [A, _]>>;
}
export const Bifunctor = <T>({ bimap }: Pick<Bifunctor<T>, 'bimap'>): Bifunctor<T> => ({
bimap,
first: <A, B>(t: $<T, [A, B]>) => ({
map: (f, u) => bimap(f, x => x, u),
}),
second: <A, B>(t: $<T, [A, B]>) => ({
map: (f, u) => bimap(x => x, f, u),
}),
});
export interface Contravariant<T> {
contramap: <A, B>(f: (x: A) => B, t: $<T, [B]>) => $<T, [A]>;
}
export interface Profunctor<T> {
promap: <A, B, C, D>(f: (x: A) => B, g: (x: C) => D, t: $<T, [B, C]>) => $<T, [A, D]>;
}
export interface Apply<T> extends Functor<T> {
ap: <A, B>(tf: $<T, [(x: A) => B]>, ta: $<T, [A]>) => $<T, [B]>;
}
export interface Applicative<T> extends Apply<T> {
of: <A>(x: A) => $<T, [A]>;
}
export const Applicative = <T>(spec: Pick<Applicative<T>, 'ap' | 'of'>): Applicative<T> => ({
...spec,
map: (f, u) => spec.ap(spec.of(f), u),
});
export interface Alt<T> extends Functor<T> {
alt: <A>(x: $<T, [A]>, y: $<T, [A]>) => $<T, [A]>;
}
export interface Plus<T> extends Alt<T> {
zero: <A>() => $<T, [A]>;
}
export interface Alternative<T> extends Applicative<T>, Plus<T> {}
export interface Chain<T> extends Apply<T> {
chain: <A, B>(f: (x: A) => $<T, [B]>, t: $<T, [A]>) => $<T, [B]>;
}
export const Chain = <T>(spec: Pick<Chain<T>, 'chain'> & Pick<Functor<T>, 'map'>): Chain<T> => ({
...spec,
ap: (uf, ux) => spec.chain(f => spec.map(f, ux), uf),
});
export interface Monad<T> extends Applicative<T>, Chain<T> {
join: <A>(tt: $<T, [$<T, [A]>]>) => $<T, [A]>;
}
export const Monad = <T>({
of,
chain,
}: Pick<Applicative<T>, 'of'> & Pick<Chain<T>, 'chain'>): Monad<T> => ({
of,
...Chain({ chain, map: (f, t) => chain(x => of(f(x)), t) }),
join: tt => chain(t => t, tt),
});
export interface Foldable<T> {
reduce: <A, B>(f: (x: A, y: B) => A, x: A, u: $<T, [B]>) => A;
}
export interface Extend<T> extends Functor<T> {
extend: <A, B>(f: (t: $<T, [A]>) => B, t: $<T, [A]>) => $<T, [B]>;
}
export interface Comonad<T> extends Extend<T> {
extract: <a>(t: $<T, [a]>) => a;
}
export interface Traversable<T> extends Functor<T>, Foldable<T> {
traverse: <U, A, B>(a: Applicative<U>, f: (x: A) => $<U, [B]>, t: $<T, [A]>) => $<U, [$<T, [B]>]>;
}