-
Notifications
You must be signed in to change notification settings - Fork 0
/
monad.ml
176 lines (126 loc) · 4.06 KB
/
monad.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
module type Basic = sig
type 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val return : 'a -> 'a t
end
module type Infix = sig
type 'a t
(** [t >>= f] returns a computation that sequences the computations represented by two
monad elements. The resulting computation first does [t] to yield a value [v], and
then runs the computation returned by [f v]. *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** [t >>| f] is [t >>= (fun a -> return (f a))]. *)
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
end
module type S = sig
(** A monad is an abstraction of the concept of sequencing of computations. A value of
type 'a monad represents a computation that returns a value of type 'a. *)
include Infix
module Monad_infix : Infix with type 'a t := 'a t
(** [bind t f] = [t >>= f] *)
val bind : 'a t -> ('a -> 'b t) -> 'b t
(** [return v] returns the (trivial) computation that returns v. *)
val return : 'a -> 'a t
(** [map t ~f] is t >>| f. *)
val map : 'a t -> f:('a -> 'b) -> 'b t
(** [join t] is [t >>= (fun t' -> t')]. *)
val join : 'a t t -> 'a t
(** [ignore t] = map t ~f:(fun _ -> ()). *)
val ignore : 'a t -> unit t
val all : 'a t list -> 'a list t
val all_ignore : unit t list -> unit t
end
module Make (M : Basic) : S with type 'a t := 'a M.t = struct
let bind = M.bind
let return = M.return
module Monad_infix = struct
let (>>=) = bind
let (>>|) t f = t >>= fun a -> return (f a)
end
include Monad_infix
let join t = t >>= fun t' -> t'
let map t ~f = t >>| f
let ignore t = map t ~f:(fun _ -> ())
let all =
let rec loop vs = function
| [] -> return (List.rev vs)
| t :: ts -> t >>= fun v -> loop (v :: vs) ts
in
fun ts -> loop [] ts
let rec all_ignore = function
| [] -> return ()
| t :: ts -> t >>= fun () -> all_ignore ts
end
(**
Multi parameter monad.
The second parameter get unified across all the computation. This is used
to encode monads working on a multi parameter data structure like
([('a,'b result)]).
*)
module type Basic2 = sig
type ('a, 'd) t
val bind : ('a, 'd) t -> ('a -> ('b, 'd) t) -> ('b, 'd) t
val return : 'a -> ('a, _) t
end
(** Same as Infix, except the monad type has two arguments. The second is always just
passed through. *)
module type Infix2 = sig
type ('a, 'd) t
val (>>=) : ('a, 'd) t -> ('a -> ('b, 'd) t) -> ('b, 'd) t
val (>>|) : ('a, 'd) t -> ('a -> 'b) -> ('b, 'd) t
end
(** The same as S except the monad type has two arguments. The second is always just
passed through. *)
module type S2 = sig
include Infix2
module Monad_infix : Infix2 with type ('a, 'd) t := ('a, 'd) t
val bind : ('a, 'd) t -> ('a -> ('b, 'd) t) -> ('b, 'd) t
val return : 'a -> ('a, _) t
val map : ('a, 'd) t -> f:('a -> 'b) -> ('b, 'd) t
val join : (('a, 'd) t, 'd) t -> ('a, 'd) t
val ignore : (_, 'd) t -> (unit, 'd) t
val all : ('a, 'd) t list -> ('a list, 'd) t
val all_ignore : (unit, 'd) t list -> (unit, 'd) t
end
module Check_S2_refines_S (X : S) : (S2 with type ('a, 'd) t = 'a X.t) =
struct
type ('a, 'd) t = 'a X.t
include struct
open X
let (>>=) = (>>=)
let (>>|) = (>>|)
let bind = bind
let return = return
let map = map
let join = join
let ignore = ignore
let all = all
let all_ignore = all_ignore
end
module Monad_infix = struct
open X.Monad_infix
let (>>=) = (>>=)
let (>>|) = (>>|)
end
end
module Make2 (M : Basic2) : S2 with type ('a, 'd) t := ('a, 'd) M.t = struct
let bind = M.bind
let return = M.return
module Monad_infix = struct
let (>>=) = bind
let (>>|) t f = t >>= fun a -> return (f a)
end
include Monad_infix
let join t = t >>= fun t' -> t'
let map t ~f = t >>| f
let ignore t = map t ~f:(fun _ -> ())
let all =
let rec loop vs = function
| [] -> return (List.rev vs)
| t :: ts -> t >>= fun v -> loop (v :: vs) ts
in
fun ts -> loop [] ts
let rec all_ignore = function
| [] -> return ()
| t :: ts -> t >>= fun () -> all_ignore ts
end