-
Notifications
You must be signed in to change notification settings - Fork 1
/
example01.ml
91 lines (70 loc) · 2.23 KB
/
example01.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
(* First example: just the option monad. *)
module P = PersistentUnionFind
(** Formulas *)
(* Conjunction of equalities. *)
type formula =
| Equals of var * var
| And of formula * formula
(** Variables as equivalence classes in a union-find. *)
(* A variable is an equivalence class that resolves to either a flexible or a
* rigid variable. The [descr] field would typically be more sophisticated. For
* instance, we may want to use levels to make sure that only legal
* instantiations are performed. *)
and descr =
| Flexible
| Rigid
(* Variables are defined using a persistent union-find data structure. *)
and var = P.point
and state = descr P.state
(** The option monad. *)
module Option = struct
let return = fun x -> Some x
let ( >>= ) x f =
match x with
| Some x -> f x
| None -> None
let nothing = None
end
open Option
(** Helpers to deal with the stateironment. *)
(* The empty stateironment *)
let empty: state = P.init ()
let bind_rigid (state: state): var * state =
P.create Rigid state
let bind_flexible (state: state): var * state =
P.create Flexible state
(* Two variables can be unified as long as one of them is flexible, or that they
* are two equal rigids. Two flexibles unify into the same flexible; a flexible
* unifies with a rigid instantiates onto that rigid. *)
let unify (state: state) (v1: var) (v2: var): state option =
match P.find v1 state, P.find v2 state with
| Flexible, Flexible
| Flexible, Rigid ->
return (P.union v1 v2 state)
| Rigid, Flexible ->
return (P.union v2 v1 state)
| Rigid, Rigid ->
if P.same v1 v2 state then
return state
else
nothing
(** Solving *)
let rec solve (state: state) (formula: formula): state option =
match formula with
| Equals (v1, v2) ->
unify state v1 v2
| And (f1, f2) ->
solve state f1 >>= fun state ->
solve state f2
let _ =
let state = empty in
let x, state = bind_rigid state in
let y, state = bind_flexible state in
let z, state = bind_rigid state in
(* x = ?y /\ z = z *)
let f1 = And (Equals (x, y), Equals (z, z)) in
(* x = ?y /\ ?y = z *)
let f2 = And (Equals (x, y), Equals (y, z)) in
assert (solve state f1 <> None);
assert (solve state f2 = None);
()