-
Notifications
You must be signed in to change notification settings - Fork 41
/
Relude_ReaderT.re
117 lines (94 loc) · 3.5 KB
/
Relude_ReaderT.re
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
open BsBastet.Interface;
open Relude_Function.Infix;
// TODO: not sure whether to just make this functor include the "Env" type R here along with the Monad, or
// have it nested inside. I have a convenience variant called WithMonadAndEnv, but maybe that should
// just be the only thing.
/**
Creates a ReaderT Monad with the given Monad module
*/
module WithMonad = (M: MONAD) => {
type t('r, 'a) =
| ReaderT('r => M.t('a));
let make: 'r 'a. ('r => M.t('a)) => t('r, 'a) = rToMA => ReaderT(rToMA);
let runReaderT: 'r 'a. ('r, t('r, 'a)) => M.t('a) =
(r, ReaderT(rToMA)) => rToMA(r);
let mapReaderT: 'r 'a 'b. (M.t('a) => M.t('b), t('r, 'a)) => t('r, 'b) =
(maToMB, ReaderT(rToMA)) => ReaderT(maToMB << rToMA);
let withReaderT: 'r1 'r2 'a. ('r2 => 'r1, t('r1, 'a)) => t('r2, 'a) =
(r2ToR1, ReaderT(r1ToMA)) => ReaderT(r1ToMA << r2ToR1);
let ask: 'r. t('r, 'r) = ReaderT(r => M.pure(r));
let asks: 'r 'a. ('r => 'a) => t('r, 'a) =
rToA => ReaderT(r => M.pure(rToA(r)));
let local: 'r 'a. ('r => 'r, t('r, 'a)) => t('r, 'a) =
(rToR, ReaderT(rToMA)) => ReaderT(r => rToMA(rToR(r)));
let map: 'r 'a 'b. ('a => 'b, t('r, 'a)) => t('r, 'b) =
(aToB, ReaderT(rToMA)) => ReaderT(r => M.map(aToB, rToMA(r)));
let apply: 'r 'a 'b. (t('r, 'a => 'b), t('r, 'a)) => t('r, 'b) =
(ReaderT(rToMAToB), ReaderT(rToMA)) =>
ReaderT(r => M.apply(rToMAToB(r), rToMA(r)));
let pure: 'r 'a. 'a => t('r, 'a) = a => ReaderT(_ => M.pure(a));
let bind: 'r 'a 'b. (t('r, 'a), 'a => t('r, 'b)) => t('r, 'b) =
(ReaderT(rToMA), aToReaderB) =>
ReaderT(
r =>
M.flat_map(
rToMA(r),
a => {
let ReaderT(rToMB) = aToReaderB(a);
rToMB(r);
},
),
);
let semiflatMap: 'r 'a 'b. ('a => M.t('b), t('r, 'a)) => t('r, 'b) =
(aToMA, ReaderT(rToMA)) =>
ReaderT(r => M.flat_map(rToMA(r), a => aToMA(a)));
/**
Locks in the reader environment type, so that we can implement the
single-type-parameter type classes.
*/
module WithEnv = (R: TYPE) => {
type nonrec t('a) = t(R.t, 'a);
let make = make;
let runReaderT = runReaderT;
let mapReaderT = mapReaderT;
let withReaderT = withReaderT;
let ask = ask;
let asks = asks;
let local = local;
let semiflatMap = semiflatMap;
module Functor: FUNCTOR with type t('a) = t('a) = {
type nonrec t('a) = t('a);
let map = map;
};
let map = Functor.map;
include Relude_Extensions_Functor.FunctorExtensions(Functor);
module Apply: APPLY with type t('a) = t('a) = {
include Functor;
let apply = apply;
};
let apply = Apply.apply;
include Relude_Extensions_Apply.ApplyExtensions(Apply);
module Applicative: APPLICATIVE with type t('a) = t('a) = {
include Apply;
let pure = pure;
};
let pure = Applicative.pure;
include Relude_Extensions_Applicative.ApplicativeExtensions(Applicative);
module Monad: MONAD with type t('a) = t('a) = {
include Applicative;
let flat_map = bind;
};
let bind = Monad.flat_map;
include Relude_Extensions_Monad.MonadExtensions(Monad);
module Infix = {
include Relude_Extensions_Functor.FunctorInfix(Functor);
include Relude_Extensions_Apply.ApplyInfix(Apply);
include Relude_Extensions_Monad.MonadInfix(Monad);
};
};
};
module WithMonadAndEnv = (M: MONAD, E: TYPE) => {
module WithMonad = WithMonad(M);
include WithMonad.WithEnv(E);
};
module Reader = WithMonad(Relude_Identity.Monad);