Source file task.ml
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
type (-'a, 'b) t = {
has_dynamic_dependencies : bool
; dependencies : Deps.t
; action : 'a -> 'b Eff.t
}
type 'a ct = (unit, 'a) t
let make ?(has_dynamic_dependencies = true) dependencies action =
{ dependencies; action; has_dynamic_dependencies }
let from_effect ?has_dynamic_dependencies action =
make ?has_dynamic_dependencies Deps.empty action
let dependencies_of { dependencies; _ } = dependencies
let action_of { action; _ } = action
let has_dynamic_dependencies { has_dynamic_dependencies; _ } =
has_dynamic_dependencies
let destruct { dependencies; action; has_dynamic_dependencies } =
(dependencies, action, has_dynamic_dependencies)
let lift ?has_dynamic_dependencies f =
let dependencies = Deps.empty in
let action x = Eff.return (f x) in
make ?has_dynamic_dependencies dependencies action
let id =
let dependencies = Deps.empty in
let action = Eff.return in
{ dependencies; action; has_dynamic_dependencies = true }
let dimap f g { dependencies; action; has_dynamic_dependencies } =
let action x = Eff.map g (action (f x)) in
{ dependencies; action; has_dynamic_dependencies }
let lmap f x = dimap f Fun.id x
let rmap f x = dimap Fun.id f x
let left { dependencies; action; has_dynamic_dependencies } =
let action = function
| Either.Left x -> Eff.map Either.left (action x)
| Either.Right x -> Eff.(map Either.right (return x))
in
{ dependencies; action; has_dynamic_dependencies }
let right { dependencies; action; has_dynamic_dependencies } =
let action = function
| Either.Right x -> Eff.map Either.right (action x)
| Either.Left x -> Eff.(map Either.left (return x))
in
{ dependencies; action; has_dynamic_dependencies }
let compose t2 t1 =
let dependencies = Deps.concat t1.dependencies t2.dependencies in
let action = Eff.(t1.action >=> t2.action) in
let has_dynamic_dependencies =
t1.has_dynamic_dependencies || t2.has_dynamic_dependencies
in
{ dependencies; action; has_dynamic_dependencies }
let rcompose t1 t2 = compose t2 t1
let pre_compose f t = compose (lift f) t
let post_compose t f = compose t (lift f)
let pre_rcompose f t = rcompose (lift f) t
let post_rcompose t f = rcompose t (lift f)
let choose t1 t2 = rcompose (left t1) (right t2)
let compose_with_dynamic_deps_merge t2 t1 =
let dependencies = Deps.concat t1.dependencies t2.dependencies in
let action x =
let open Eff.Syntax in
let* v, adeps = t1.action x in
let* r, bdeps = t2.action v in
Eff.return (r, Deps.concat adeps bdeps)
in
let has_dynamic_dependencies =
t1.has_dynamic_dependencies || t2.has_dynamic_dependencies
in
{ dependencies; action; has_dynamic_dependencies }
let rcompose_with_dynamic_deps_merge t1 t2 =
compose_with_dynamic_deps_merge t2 t1
let fan_in t1 t2 =
post_rcompose (choose t1 t2) (function
| Either.Left x -> x
| Either.Right x -> x)
let first { dependencies; action; has_dynamic_dependencies } =
let action (x, y) = Eff.map (fun x -> (x, y)) (action x) in
{ dependencies; action; has_dynamic_dependencies }
let second { dependencies; action; has_dynamic_dependencies } =
let action (x, y) = Eff.map (fun y -> (x, y)) (action y) in
{ dependencies; action; has_dynamic_dependencies }
let split t1 t2 = rcompose (first t1) (second t2)
let uncurry t = rmap (fun (f, x) -> f x) (first t)
let fan_out t1 t2 = pre_rcompose (fun x -> (x, x)) (split t1 t2)
let apply =
let has_dynamic_dependencies = true in
let dependencies = Deps.empty in
let action ({ action; _ }, x) = action x in
{ dependencies; action; has_dynamic_dependencies }
let pure x = lift (fun _ -> x)
let map f x = post_rcompose x f
let ap t1 t2 = pre_compose (fun (f, x) -> f x) (fan_out t1 t2)
let select f t =
rcompose f
(fan_in
(post_rcompose
(pre_rcompose (fun x -> ((), x)) (first t))
(fun (f, x) -> f x))
(lift (fun x -> x)))
let branch s l r =
select
(select
(map Either.(map_right left) s)
(map (fun f x -> Either.right @@ f x) l))
r
let replace x t = map (fun _ -> x) t
let void t = replace () t
let zip t1 t2 = ap (map (fun a b -> (a, b)) t1) t2
let map2 fu a b = ap (map fu a) b
let map3 fu a b c = ap (map2 fu a b) c
let map4 fu a b c d = ap (map3 fu a b c) d
let map5 fu a b c d e = ap (map4 fu a b c d) e
let map6 fu a b c d e f = ap (map5 fu a b c d e) f
let map7 fu a b c d e f g = ap (map6 fu a b c d e f) g
let map8 fu a b c d e f g h = ap (map7 fu a b c d e f g) h
let no_dynamic_deps t =
let a = rcompose t (lift (fun x -> (x, Deps.empty))) in
{ a with has_dynamic_dependencies = false }
let drop_first () = lift Stdlib.snd
let drop_second () = lift Stdlib.fst
let with_dynamic_dependencies files =
let set = Deps.from_list files in
lift (fun x -> (x, set))
let empty_body () = lift (fun x -> (x, ""))
let const k = lift (fun _ -> k)
module Infix = struct
let ( <<< ) = compose
let ( >>> ) = rcompose
let ( <+< ) = compose_with_dynamic_deps_merge
let ( >+> ) = rcompose_with_dynamic_deps_merge
let ( *<< ) f t = make Deps.empty f <<< t
let ( <<* ) t f = t <<< make Deps.empty f
let ( |<< ) = pre_compose
let ( <<| ) = post_compose
let ( *>> ) f t = make Deps.empty f >>> t
let ( >>* ) t f = t >>> make Deps.empty f
let ( |>> ) = pre_rcompose
let ( >>| ) = post_rcompose
let ( +++ ) = choose
let ( ||| ) = fan_in
let ( *** ) = split
let ( &&& ) = fan_out
let ( <$> ) = map
let ( <*> ) = ap
let ( <*? ) = select
let ( ||> ) x f = f x
end
module Syntax = struct
let ( let+ ) x f = map f x
let ( and+ ) = zip
end
include Infix
include Syntax
module Static = struct
let on_content arr = second arr
let on_metadata arr = first arr
let keep_content = drop_first
let empty_body = empty_body
end
module Dynamic = struct
let on_content arr = first (Static.on_content arr)
let on_metadata arr = first (Static.on_metadata arr)
let on_dependencies arr = second arr
let keep_content () = lift (fun ((_, c), d) -> (c, d))
let empty_body () = lift (fun (x, d) -> ((x, ""), d))
end