-
Notifications
You must be signed in to change notification settings - Fork 0
/
prolog.ml
177 lines (136 loc) · 6.51 KB
/
prolog.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
(* ========================================================================= *)
(* Backchaining procedure for Horn clauses, and toy Prolog implementation. *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* Rename a rule. *)
(* ------------------------------------------------------------------------- *)
let renamerule k (asm,c) =
let fvs = fv(list_conj(c::asm)) in
let n = length fvs in
let vvs = map (fun i -> "_" ^ string_of_int i) (k -- (k+n-1)) in
let inst = subst(fpf fvs (map (fun x -> Var x) vvs)) in
(map inst asm,inst c),k+n;;
(* ------------------------------------------------------------------------- *)
(* Basic prover for Horn clauses based on backchaining with unification. *)
(* ------------------------------------------------------------------------- *)
let rec backchain rules n k env goals =
match goals with
[] -> env
| g::gs ->
if n = 0 then failwith "Too deep" else
tryfind (fun rule ->
let (a,c),k' = renamerule k rule in
backchain rules (n - 1) k' (unify_literals env (c,g)) (a @ gs))
rules;;
let hornify cls =
let pos,neg = partition positive cls in
if length pos > 1 then failwith "non-Horn clause"
else (map negate neg,if pos = [] then False else hd pos);;
let hornprove fm =
let rules = map hornify (simpcnf(skolemize(Not(generalize fm)))) in
deepen (fun n -> backchain rules n 0 undefined [False],n) 0;;
(* ------------------------------------------------------------------------- *)
(* A Horn example. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
let p32 = hornprove
<<(forall x. P(x) /\ (G(x) \/ H(x)) ==> Q(x)) /\
(forall x. Q(x) /\ H(x) ==> J(x)) /\
(forall x. R(x) ==> H(x))
==> (forall x. P(x) /\ R(x) ==> J(x))>>;;
(* ------------------------------------------------------------------------- *)
(* A non-Horn example. *)
(* ------------------------------------------------------------------------- *)
(****************
hornprove <<(p \/ q) /\ (~p \/ q) /\ (p \/ ~q) ==> ~(~q \/ ~q)>>;;
**********)
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Parsing rules in a Prolog-like syntax. *)
(* ------------------------------------------------------------------------- *)
let parserule s =
let c,rest =
parse_formula (parse_infix_atom,parse_atom) [] (lex(explode s)) in
let asm,rest1 =
if rest <> [] & hd rest = ":-"
then parse_list ","
(parse_formula (parse_infix_atom,parse_atom) []) (tl rest)
else [],rest in
if rest1 = [] then (asm,c) else failwith "Extra material after rule";;
(* ------------------------------------------------------------------------- *)
(* Prolog interpreter: just use depth-first search not iterative deepening. *)
(* ------------------------------------------------------------------------- *)
let simpleprolog rules gl =
backchain (map parserule rules) (-1) 0 undefined [parse gl];;
(* ------------------------------------------------------------------------- *)
(* Ordering example. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
let lerules = ["0 <= X"; "S(X) <= S(Y) :- X <= Y"];;
simpleprolog lerules "S(S(0)) <= S(S(S(0)))";;
(*** simpleprolog lerules "S(S(0)) <= S(0)";;
***)
let env = simpleprolog lerules "S(S(0)) <= X";;
apply env "X";;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* With instantiation collection to produce a more readable result. *)
(* ------------------------------------------------------------------------- *)
let prolog rules gl =
let i = solve(simpleprolog rules gl) in
mapfilter (fun x -> Atom(R("=",[Var x; apply i x]))) (fv(parse gl));;
(* ------------------------------------------------------------------------- *)
(* Example again. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
prolog lerules "S(S(0)) <= X";;
(* ------------------------------------------------------------------------- *)
(* Append example, showing symmetry between inputs and outputs. *)
(* ------------------------------------------------------------------------- *)
let appendrules =
["append(nil,L,L)"; "append(H::T,L,H::A) :- append(T,L,A)"];;
prolog appendrules "append(1::2::nil,3::4::nil,Z)";;
prolog appendrules "append(1::2::nil,Y,1::2::3::4::nil)";;
prolog appendrules "append(X,3::4::nil,1::2::3::4::nil)";;
prolog appendrules "append(X,Y,1::2::3::4::nil)";;
(* ------------------------------------------------------------------------- *)
(* However this way round doesn't work. *)
(* ------------------------------------------------------------------------- *)
(***
*** prolog appendrules "append(X,3::4::nil,X)";;
***)
(* ------------------------------------------------------------------------- *)
(* A sorting example (from Lloyd's "Foundations of Logic Programming"). *)
(* ------------------------------------------------------------------------- *)
let sortrules =
["sort(X,Y) :- perm(X,Y),sorted(Y)";
"sorted(nil)";
"sorted(X::nil)";
"sorted(X::Y::Z) :- X <= Y, sorted(Y::Z)";
"perm(nil,nil)";
"perm(X::Y,U::V) :- delete(U,X::Y,Z), perm(Z,V)";
"delete(X,X::Y,Y)";
"delete(X,Y::Z,Y::W) :- delete(X,Z,W)";
"0 <= X";
"S(X) <= S(Y) :- X <= Y"];;
prolog sortrules
"sort(S(S(S(S(0))))::S(0)::0::S(S(0))::S(0)::nil,X)";;
(* ------------------------------------------------------------------------- *)
(* Yet with a simple swap of the first two predicates... *)
(* ------------------------------------------------------------------------- *)
let badrules =
["sort(X,Y) :- sorted(Y), perm(X,Y)";
"sorted(nil)";
"sorted(X::nil)";
"sorted(X::Y::Z) :- X <= Y, sorted(Y::Z)";
"perm(nil,nil)";
"perm(X::Y,U::V) :- delete(U,X::Y,Z), perm(Z,V)";
"delete(X,X::Y,Y)";
"delete(X,Y::Z,Y::W) :- delete(X,Z,W)";
"0 <= X";
"S(X) <= S(Y) :- X <= Y"];;
(*** This no longer works
prolog badrules
"sort(S(S(S(S(0))))::S(0)::0::S(S(0))::S(0)::nil,X)";;
***)
END_INTERACTIVE;;