-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtypeclasses.ml
152 lines (94 loc) · 3.15 KB
/
typeclasses.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
(*
typeclasses.ml -- the typeclass hierarchy used in `drome`
ApplicativeError ----- MonadError
/ /
/ /
/ /
Functor ---- Applicative ----- Monad
*)
open Util
module type Functor = sig
type _ f
val map : ('a -> 'b) -> 'a f -> 'b f
val ( <$> ) : 'a f -> ('a -> 'b) -> 'b f
val void : 'a f -> unit f
end
module type Applicative = sig
type _ f
val pure : 'a -> 'a f
val ap : ('a -> 'b) f -> 'a f -> 'b f
val ( <*> ) : ('a -> 'b) f -> 'a f -> 'b f
val zip : 'a f -> 'b f -> ('a * 'b) f
val ( >*< ) : 'a f -> 'b f -> ('a * 'b) f
end
(* Implement BaseMonad and use MakeMonad functor for extended API and syntax *)
module type BaseMonad = sig
type _ f
val return : 'a -> 'a f
val bind : ('a -> 'b f) -> 'a f -> 'b f
end
module type Monad = sig
type _ f
val return : 'a -> 'a f
val bind : ('a -> 'b f) -> 'a f -> 'b f
val ( >>= ) : 'a f -> ('a -> 'b f) -> 'b f
val ( >=> ) : ('a -> 'b f) -> ('b -> 'c f) -> 'a -> 'c f
val productR : 'a f -> 'b f -> 'b f
val ( *> ) : 'a f -> 'b f -> 'b f
val productL : 'a f -> 'b f -> 'a f
val ( <* ) : 'a f -> 'b f -> 'a f
end
module type ApplicativeError = sig
type _ f
val raise_error : exn -> 'a f
val handle_error_with : (exn -> 'a f) -> 'a f -> 'a f
val handle_error : (exn -> 'a) -> 'a f -> 'a f
val attempt : 'a f -> ('a, exn) result f
val adapt_error : (exn -> exn) -> 'a f -> 'a f
end
module type MonadError = sig
type _ f
val rethrow : ('a, exn) result f -> 'a f
val ensure : ('a -> bool) -> exn -> 'a f -> 'a f
end
(* Extend BaseMonad with nice syntax & derived operators *)
module MakeMonad (M : BaseMonad) : Monad with type 'a f = 'a M.f = struct
type 'a f = 'a M.f
let return = M.return
let bind = M.bind
let ( >>= ) af f = bind f af
let ( >=> ) (f : 'a -> 'b f) (g : 'b -> 'c f) (a : 'a) : 'c f = f a >>= g
let productR (a : 'a f) (b : 'b f) : 'b f = a >>= fun _ -> b
let ( *> ) = productR
let productL (a : 'a f) (b : 'b f) : 'a f = a >>= fun a' -> b *> return a'
let ( <* ) = productL
end
(* Derive Applicative from Monad *)
module MakeApplicative (M : Monad) : Applicative with type 'a f = 'a M.f =
struct
open M
type 'a f = 'a M.f
let pure = return
let ap (ff : ('a -> 'b) M.f) (fa : 'a M.f) : 'b M.f =
ff >>= fun f ->
fa >>= fun a -> return (f a)
let ( <*> ) = ap
let zip af ab = pure (fun a b -> (a, b)) <*> af <*> ab
let ( >*< ) = zip
end
(* Derive Functor via Applicative *)
module MakeFunctor (A : Applicative) : Functor with type 'a f = 'a A.f = struct
open A
type 'a f = 'a A.f
let map f fa = pure f <*> fa
let ( <$> ) fa f = map f fa
let void fa = map (fun _ -> ()) fa
end
(* Derive MonadError from ApplicativeError and Monad *)
module MakeMonadError (A : ApplicativeError) (M : Monad with type 'a f = 'a A.f) :
MonadError with type 'a f = 'a M.f = struct
type 'a f = 'a M.f
let rethrow ioa = M.bind (Result.fold ~ok:M.return ~error:A.raise_error) ioa
let ensure p e io =
M.bind (fun a -> if p a then M.return a else A.raise_error e) io
end