Skip to content

Commit 9e1ab00

Browse files
David PeterDavid Peter
authored andcommitted
draft: Do, bind, bindTo
1 parent bef134e commit 9e1ab00

4 files changed

Lines changed: 140 additions & 88 deletions

File tree

chain.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,48 @@ import type { Apply } from "./apply.ts";
77
*/
88
export interface Chain<U extends Kind> extends TypeClass<U>, Apply<U> {
99
readonly chain: <A, I, J = never, K = never, D = unknown, E = unknown>(
10-
fati: (a: A) => $<U, [I, J, K], [D], [E]>,
10+
fati: (a: A) => $<U, [I, J, K], [D], [E]>
1111
) => <B = never, C = never>(
12-
ta: $<U, [A, B, C], [D], [E]>,
12+
ta: $<U, [A, B, C], [D], [E]>
1313
) => $<U, [I, B | J, C | K], [D], [E]>;
1414
}
15+
16+
/**
17+
* ChainRec
18+
* https://github.com/fantasyland/static-land/blob/master/docs/spec.md#chain
19+
*/
20+
export interface ChainRec<U extends Kind> extends TypeClass<U>, Chain<U> {
21+
readonly chainRec: <A, B, I, J = never, K = never, D = unknown, E = unknown>(
22+
fati: (a: A) => $<U, [I, J, K], [D], [E]>,
23+
a: A
24+
) => $<U, [B, J, K], [D], [E]>;
25+
}
26+
27+
// chainFirst
28+
export function chainFirst<U extends Kind>(
29+
M: Chain<U>
30+
): <A, I, J = never, K = never, D = unknown, E = unknown>(
31+
f: (a: A) => $<U, [I, J, K], [D], [E]>
32+
) => <B, C>(ma: $<U, [A, B, C], [D], [E]>) => $<U, [A, B, C], [D], [E]> {
33+
return (f) => (ma) => M.chain((a) => M.map(() => a)(f(a)))(ma);
34+
}
35+
36+
// bind
37+
export function bind<U extends Kind>(
38+
M: Chain<U>
39+
): <N extends string, A, I, J = never, K = never, D = unknown, E = unknown>(
40+
name: Exclude<N, keyof A>,
41+
f: (a: A) => $<U, [I, J, K], [D], [E]>
42+
) => <B, C>(
43+
ma: $<U, [A, B, C], [D], [E]>
44+
) => $<
45+
U,
46+
[{ readonly [K in keyof A | N]: K extends keyof A ? A[K] : I }],
47+
[D],
48+
[E]
49+
> {
50+
return (name, f) =>
51+
M.chain((a) =>
52+
M.map((b) => Object.assign({}, a, { [name]: b }) as any)(f(a))
53+
);
54+
}

either.ts

Lines changed: 68 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import * as O from "./option.ts";
1717
import { isNotNil } from "./nilable.ts";
1818
import { fromCompare } from "./ord.ts";
1919
import { flow, pipe } from "./fn.ts";
20+
import { bind as bind_ } from "./chain.ts";
21+
import { bindTo as bindTo_ } from "./functor.ts";
2022

2123
export type Left<L> = { tag: "Left"; left: L };
2224

@@ -33,11 +35,11 @@ export interface RightURI<B> extends Kind {
3335
}
3436

3537
export function left<E, A = never>(left: E): Either<E, A> {
36-
return ({ tag: "Left", left });
38+
return { tag: "Left", left };
3739
}
3840

3941
export function right<A, E = never>(right: A): Either<E, A> {
40-
return ({ tag: "Right", right });
42+
return { tag: "Right", right };
4143
}
4244

4345
export function of<A, B = never>(a: A): Either<B, A> {
@@ -49,14 +51,13 @@ export function throwError<A = never, B = never>(b: B): Either<B, A> {
4951
}
5052

5153
export function fromNullable<E>(fe: () => E) {
52-
return <A>(
53-
a: A,
54-
): Either<E, NonNullable<A>> => (isNotNil(a) ? right(a) : left(fe()));
54+
return <A>(a: A): Either<E, NonNullable<A>> =>
55+
isNotNil(a) ? right(a) : left(fe());
5556
}
5657

5758
export function tryCatch<E, A>(
5859
fa: () => A,
59-
onError: (e: unknown) => E,
60+
onError: (e: unknown) => E
6061
): Either<E, A> {
6162
try {
6263
return right(fa());
@@ -67,7 +68,7 @@ export function tryCatch<E, A>(
6768

6869
export function tryCatchWrap<E, A, AS extends unknown[]>(
6970
fn: (...as: AS) => A,
70-
onError: (e: unknown) => E,
71+
onError: (e: unknown) => E
7172
): (...as: AS) => Either<E, A> {
7273
return (...as: AS) => {
7374
try {
@@ -80,24 +81,24 @@ export function tryCatchWrap<E, A, AS extends unknown[]>(
8081

8182
export function fromPredicate<E, A, B extends A>(
8283
refinement: Refinement<A, B>,
83-
onFalse: (a: A) => E,
84+
onFalse: (a: A) => E
8485
): (a: A) => Either<E, B>;
8586
export function fromPredicate<E, A>(
8687
predicate: Predicate<A>,
87-
onFalse: (a: A) => E,
88+
onFalse: (a: A) => E
8889
): (a: A) => Either<E, A> {
89-
return (a: A) => predicate(a) ? right(a) : left(onFalse(a));
90+
return (a: A) => (predicate(a) ? right(a) : left(onFalse(a)));
9091
}
9192

9293
export function match<L, R, B>(
9394
onLeft: (left: L) => B,
94-
onRight: (right: R) => B,
95+
onRight: (right: R) => B
9596
): (ta: Either<L, R>) => B {
96-
return (ta) => isLeft(ta) ? onLeft(ta.left) : onRight(ta.right);
97+
return (ta) => (isLeft(ta) ? onLeft(ta.left) : onRight(ta.right));
9798
}
9899

99100
export function getOrElse<E, A>(onLeft: (e: E) => A) {
100-
return (ma: Either<E, A>): A => isLeft(ma) ? onLeft(ma.left) : ma.right;
101+
return (ma: Either<E, A>): A => (isLeft(ma) ? onLeft(ma.left) : ma.right);
101102
}
102103

103104
export function getRight<E, A>(ma: Either<E, A>): O.Option<A> {
@@ -116,23 +117,17 @@ export function isRight<L, R>(m: Either<L, R>): m is Right<R> {
116117
return m.tag === "Right";
117118
}
118119

119-
export function getShow<A, B>(
120-
SB: Show<B>,
121-
SA: Show<A>,
122-
): Show<Either<B, A>> {
123-
return ({
120+
export function getShow<A, B>(SB: Show<B>, SA: Show<A>): Show<Either<B, A>> {
121+
return {
124122
show: match(
125123
(left) => `Left(${SB.show(left)})`,
126-
(right) => `Right(${SA.show(right)})`,
124+
(right) => `Right(${SA.show(right)})`
127125
),
128-
});
126+
};
129127
}
130128

131-
export function getEq<A, B>(
132-
SB: Eq<B>,
133-
SA: Eq<A>,
134-
): Eq<Either<B, A>> {
135-
return ({
129+
export function getEq<A, B>(SB: Eq<B>, SA: Eq<A>): Eq<Either<B, A>> {
130+
return {
136131
equals: (b) => (a) => {
137132
if (isLeft(a)) {
138133
if (isLeft(b)) {
@@ -146,69 +141,70 @@ export function getEq<A, B>(
146141
}
147142
return SA.equals(b.right)(a.right);
148143
},
149-
});
144+
};
150145
}
151146

152-
export function getOrd<A, B>(
153-
OB: Ord<B>,
154-
OA: Ord<A>,
155-
): Ord<Either<B, A>> {
147+
export function getOrd<A, B>(OB: Ord<B>, OA: Ord<A>): Ord<Either<B, A>> {
156148
return fromCompare((fst, snd) =>
157149
isLeft(fst)
158-
? isLeft(snd) ? OB.compare(fst.left, snd.left) : -1
150+
? isLeft(snd)
151+
? OB.compare(fst.left, snd.left)
152+
: -1
159153
: isLeft(snd)
160154
? 1
161155
: OA.compare(fst.right, snd.right)
162156
);
163157
}
164158

165159
export function getLeftSemigroup<E = never, A = never>(
166-
SE: Semigroup<E>,
160+
SE: Semigroup<E>
167161
): Semigroup<Either<E, A>> {
168-
return ({
162+
return {
169163
concat: (x) => (y) =>
170164
isRight(x) ? x : isRight(y) ? y : left(SE.concat(x.left)(y.left)),
171-
});
165+
};
172166
}
173167

174168
export function getRightSemigroup<E = never, A = never>(
175-
SA: Semigroup<A>,
169+
SA: Semigroup<A>
176170
): Semigroup<Either<E, A>> {
177-
return ({
171+
return {
178172
concat: (x) => (y) =>
179173
isLeft(x) ? x : isLeft(y) ? y : right(SA.concat(x.right)(y.right)),
180-
});
174+
};
181175
}
182176

183177
export function getRightMonoid<E = never, A = never>(
184-
MA: Monoid<A>,
178+
MA: Monoid<A>
185179
): Monoid<Either<E, A>> {
186-
return ({
180+
return {
187181
...getRightSemigroup(MA),
188182
empty: () => right(MA.empty()),
189-
});
183+
};
190184
}
191185

192-
export function getRightMonad<E>(
193-
{ concat }: Semigroup<E>,
194-
): Monad<RightURI<E>> {
195-
return ({
186+
export function getRightMonad<E>({ concat }: Semigroup<E>): Monad<RightURI<E>> {
187+
return {
196188
of,
197189
ap: (ua) => (ufai) =>
198190
isLeft(ufai)
199-
? (isLeft(ua) ? left(concat(ua.left)(ufai.left)) : ufai)
200-
: (isLeft(ua) ? ua : right(ufai.right(ua.right))),
191+
? isLeft(ua)
192+
? left(concat(ua.left)(ufai.left))
193+
: ufai
194+
: isLeft(ua)
195+
? ua
196+
: right(ufai.right(ua.right)),
201197
map,
202198
join,
203199
chain,
204-
});
200+
};
205201
}
206202

207203
export function bimap<A, B, I, J>(
208204
fbj: (b: B) => J,
209-
fai: (a: A) => I,
205+
fai: (a: A) => I
210206
): (ta: Either<B, A>) => Either<J, I> {
211-
return (ta) => isLeft(ta) ? left(fbj(ta.left)) : right(fai(ta.right));
207+
return (ta) => (isLeft(ta) ? left(fbj(ta.left)) : right(fai(ta.right)));
212208
}
213209

214210
export function swap<E, A>(ma: Either<E, A>): Either<A, E> {
@@ -217,71 +213,71 @@ export function swap<E, A>(ma: Either<E, A>): Either<A, E> {
217213

218214
export function stringifyJSON<E>(
219215
u: unknown,
220-
onError: (reason: unknown) => E,
216+
onError: (reason: unknown) => E
221217
): Either<E, string> {
222218
return tryCatch(() => JSON.stringify(u), onError);
223219
}
224220

225221
export function map<A, I>(
226-
fai: (a: A) => I,
222+
fai: (a: A) => I
227223
): <B>(ta: Either<B, A>) => Either<B, I> {
228-
return (ta) => isLeft(ta) ? ta : right(fai(ta.right));
224+
return (ta) => (isLeft(ta) ? ta : right(fai(ta.right)));
229225
}
230226

231227
export function chainLeft<B, I, J>(
232-
fbj: (b: B) => Either<J, I>,
228+
fbj: (b: B) => Either<J, I>
233229
): <A>(ta: Either<B, A>) => Either<J, A | I> {
234230
return (tab) => (isLeft(tab) ? fbj(tab.left) : tab);
235231
}
236232

237233
export function ap<A, B>(
238-
ua: Either<B, A>,
234+
ua: Either<B, A>
239235
): <I, J>(ufai: Either<J, (a: A) => I>) => Either<B | J, I> {
240236
return (ufai) =>
241237
isLeft(ua) ? ua : isLeft(ufai) ? ufai : right(ufai.right(ua.right));
242238
}
243239

244240
export function chain<A, I, J>(
245-
fati: (a: A) => Either<J, I>,
241+
fati: (a: A) => Either<J, I>
246242
): <B>(ta: Either<B, A>) => Either<B | J, I> {
247-
return (ta) => isLeft(ta) ? ta : fati(ta.right);
243+
return (ta) => (isLeft(ta) ? ta : fati(ta.right));
248244
}
249245

250246
export function join<A, B, J = never>(
251-
ta: Either<J, Either<B, A>>,
247+
ta: Either<J, Either<B, A>>
252248
): Either<B | J, A> {
253249
return isLeft(ta) ? ta : ta.right;
254250
}
255251

256252
export function mapLeft<B, J>(
257-
fbj: (b: B) => J,
253+
fbj: (b: B) => J
258254
): <A>(ta: Either<B, A>) => Either<J, A> {
259-
return (ta) => isLeft(ta) ? left(fbj(ta.left)) : ta;
255+
return (ta) => (isLeft(ta) ? left(fbj(ta.left)) : ta);
260256
}
261257

262258
export function alt<A, J>(
263-
tb: Either<J, A>,
259+
tb: Either<J, A>
264260
): <B>(ta: Either<B, A>) => Either<B | J, A> {
265-
return (ta) => isLeft(ta) ? tb : ta;
261+
return (ta) => (isLeft(ta) ? tb : ta);
266262
}
267263

268264
export function extend<A, I, B>(
269-
ftai: (ta: Either<B, A>) => I,
265+
ftai: (ta: Either<B, A>) => I
270266
): (ta: Either<B, A>) => Either<B, I> {
271267
return (ta) => right(ftai(ta));
272268
}
273269

274270
export function reduce<A, O>(
275271
foao: (o: O, a: A) => O,
276-
o: O,
272+
o: O
277273
): <B>(ta: Either<B, A>) => O {
278-
return (ta) => isLeft(ta) ? o : foao(o, ta.right);
274+
return (ta) => (isLeft(ta) ? o : foao(o, ta.right));
279275
}
280276

281277
export function traverse<V extends Kind>(
282-
A: Applicative<V>,
278+
A: Applicative<V>
283279
): <A, I, J, K, L, M>(
284-
faui: (a: A) => $<V, [I, J, K], [L], [M]>,
280+
faui: (a: A) => $<V, [I, J, K], [L], [M]>
285281
) => <B>(ta: Either<B, A>) => $<V, [Either<B, I>, J, K], [L], [M]> {
286282
//deno-lint-ignore no-explicit-any
287283
const onLeft: any = flow(left, A.of);
@@ -298,6 +294,12 @@ export const MonadEither: Monad<URI> = {
298294
chain,
299295
};
300296

297+
export function Do() {
298+
return of({});
299+
}
300+
export const bind = bind_(MonadEither);
301+
export const bindTo = bindTo_(MonadEither);
302+
301303
export const BifunctorEither: Bifunctor<URI> = { bimap, mapLeft };
302304

303305
export const AltEither: Alt<URI> = { alt, map };

functor.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@ import type { $, Kind, TypeClass } from "./kind.ts";
66
*/
77
export interface Functor<U extends Kind> extends TypeClass<U> {
88
readonly map: <A, I>(
9-
fai: (value: A) => I,
9+
fai: (value: A) => I
1010
) => <B = never, C = never, D = unknown, E = unknown>(
11-
ta: $<U, [A, B, C], [D], [E]>,
11+
ta: $<U, [A, B, C], [D], [E]>
1212
) => $<U, [I, B, C], [D], [E]>;
1313
}
14+
15+
export function bindTo<U extends Kind>(
16+
F: Functor<U>
17+
): <N extends string>(
18+
name: N
19+
) => <A = never, B = never, C = never, D = unknown, E = unknown>(
20+
fa: $<U, [A, B, C], [D], [E]>
21+
) => $<U, [{ readonly [K in N]: A }, B, C], [D], [E]> {
22+
return (name) => F.map((a) => ({ [name]: a } as any));
23+
}

0 commit comments

Comments
 (0)