-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapply.ts
More file actions
73 lines (60 loc) · 2.59 KB
/
apply.ts
File metadata and controls
73 lines (60 loc) · 2.59 KB
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
import { MinBox1 } from 'data/kind'
import { Functor } from 'ghc/base/functor'
import { Applicative, applicative as createApplicative } from 'ghc/base/applicative'
import { FunctionArrow, FunctionArrow2 } from 'ghc/prim/function-arrow'
import { id, $const } from 'ghc/base/functions'
// Apply: Functor with application, but without pure
export type ApplyBase = Functor & {
'<*>'<A, B>(f: MinBox1<FunctionArrow<A, B>>, fa: MinBox1<A>): MinBox1<B>
liftA2<A, B, C>(f: FunctionArrow2<A, B, C>, fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<C>
}
export type Apply = ApplyBase & {
'*>'<A, B>(fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<B>
'<*'<A, B>(fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<A>
'<**>'<A, B>(fa: MinBox1<A>, f: MinBox1<FunctionArrow<A, B>>): MinBox1<B>
}
export type BaseImplementation = Partial<Pick<ApplyBase, '<*>' | 'liftA2'>> &
(Pick<ApplyBase, '<*>'> | Pick<ApplyBase, 'liftA2'>)
const extensions = (base: ApplyBase) => ({
// u *> v = (id <$ u) <*> v
'*>': <A, B>(fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<B> => base['<*>'](base['<$'](id, fa), fb),
// u <* v = liftA2 const u v
'<*': <A, B>(fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<A> => base.liftA2($const, fa, fb),
// (<**>) = liftA2 (\a f -> f a)
'<**>': <A, B>(fa: MinBox1<A>, f: MinBox1<FunctionArrow<A, B>>): MinBox1<B> =>
base.liftA2(
<A, C>(a: A) =>
(b: (_: A) => C) =>
b(a) as C,
fa,
f,
),
})
export const apply = (base: BaseImplementation, fBase: Functor): Apply => {
const star = base['<*>']
const lift = base.liftA2
const applyBase = {
...fBase,
...base,
'<*>': star,
liftA2: lift,
} as ApplyBase
if (star && !lift) {
// liftA2 f x y = f <$> x <*> y
applyBase.liftA2 = <A, B, C>(f: FunctionArrow2<A, B, C>, fa: MinBox1<A>, fb: MinBox1<B>): MinBox1<C> =>
star(fBase['<$>'](f, fa), fb)
}
if (!star && lift) {
// (<*>) = liftA2 id
applyBase['<*>'] = <A, B>(f: MinBox1<FunctionArrow<A, B>>, fa: MinBox1<A>): MinBox1<B> => lift(id, f, fa)
}
return {
...applyBase,
...extensions(applyBase),
}
}
// Helper: derive Apply from an existing Applicative (drops pure)
export const fromApplicative = (app: Applicative): Apply => apply({ '<*>': app['<*>'], liftA2: app.liftA2 }, app)
// Helper: construct an Applicative from an Apply and a `pure`
export const toApplicative = (ap: Apply, pure: <A>(a: NonNullable<A>) => MinBox1<A>): Applicative =>
createApplicative({ pure, '<*>': ap['<*>'], liftA2: ap.liftA2 }, ap)