1 (* ========================================================================= *) |
1 (* ========================================================================= *) |
2 (* FIRST ORDER LOGIC SUBSTITUTIONS *) |
2 (* FIRST ORDER LOGIC SUBSTITUTIONS *) |
3 (* Copyright (c) 2002-2006 Joe Hurd, distributed under the BSD License *) |
3 (* Copyright (c) 2002-2006 Joe Hurd, distributed under the BSD License *) |
4 (* ========================================================================= *) |
4 (* ========================================================================= *) |
5 |
5 |
6 structure Subst :> Subst = |
6 structure Subst :> Subst = |
7 struct |
7 struct |
8 |
8 |
28 |
28 |
29 fun insert (Subst m) v_tm = Subst (NameMap.insert m v_tm); |
29 fun insert (Subst m) v_tm = Subst (NameMap.insert m v_tm); |
30 |
30 |
31 fun singleton v_tm = insert empty v_tm; |
31 fun singleton v_tm = insert empty v_tm; |
32 |
32 |
33 local |
|
34 fun compatible (tm1,tm2) = |
|
35 if tm1 = tm2 then SOME tm1 else raise Error "Subst.union: incompatible"; |
|
36 in |
|
37 fun union (s1 as Subst m1) (s2 as Subst m2) = |
|
38 if NameMap.null m1 then s2 |
|
39 else if NameMap.null m2 then s1 |
|
40 else Subst (NameMap.union compatible m1 m2); |
|
41 end; |
|
42 |
|
43 fun toList (Subst m) = NameMap.toList m; |
33 fun toList (Subst m) = NameMap.toList m; |
44 |
34 |
45 fun fromList l = Subst (NameMap.fromList l); |
35 fun fromList l = Subst (NameMap.fromList l); |
46 |
36 |
47 fun foldl f b (Subst m) = NameMap.foldl f b m; |
37 fun foldl f b (Subst m) = NameMap.foldl f b m; |
48 |
38 |
49 fun foldr f b (Subst m) = NameMap.foldr f b m; |
39 fun foldr f b (Subst m) = NameMap.foldr f b m; |
50 |
40 |
51 fun pp ppstrm sub = |
41 fun pp sub = |
52 Parser.ppBracket "<[" "]>" |
42 Print.ppBracket "<[" "]>" |
53 (Parser.ppSequence "," (Parser.ppBinop " |->" Parser.ppString Term.pp)) |
43 (Print.ppOpList "," (Print.ppOp2 " |->" Name.pp Term.pp)) |
54 ppstrm (toList sub); |
44 (toList sub); |
55 |
45 |
56 val toString = Parser.toString pp; |
46 val toString = Print.toString pp; |
57 |
47 |
58 (* ------------------------------------------------------------------------- *) |
48 (* ------------------------------------------------------------------------- *) |
59 (* Normalizing removes identity substitutions. *) |
49 (* Normalizing removes identity substitutions. *) |
60 (* ------------------------------------------------------------------------- *) |
50 (* ------------------------------------------------------------------------- *) |
61 |
51 |
76 |
66 |
77 fun subst sub = |
67 fun subst sub = |
78 let |
68 let |
79 fun tmSub (tm as Term.Var v) = |
69 fun tmSub (tm as Term.Var v) = |
80 (case peek sub v of |
70 (case peek sub v of |
81 SOME tm' => if Sharing.pointerEqual (tm,tm') then tm else tm' |
71 SOME tm' => if Portable.pointerEqual (tm,tm') then tm else tm' |
82 | NONE => tm) |
72 | NONE => tm) |
83 | tmSub (tm as Term.Fn (f,args)) = |
73 | tmSub (tm as Term.Fn (f,args)) = |
84 let |
74 let |
85 val args' = Sharing.map tmSub args |
75 val args' = Sharing.map tmSub args |
86 in |
76 in |
87 if Sharing.pointerEqual (args,args') then tm |
77 if Portable.pointerEqual (args,args') then tm |
88 else Term.Fn (f,args') |
78 else Term.Fn (f,args') |
89 end |
79 end |
90 in |
80 in |
91 fn tm => if null sub then tm else tmSub tm |
81 fn tm => if null sub then tm else tmSub tm |
92 end; |
82 end; |
125 in |
115 in |
126 if null sub2 then sub1 else NameMap.foldl f sub2 m1 |
116 if null sub2 then sub1 else NameMap.foldl f sub2 m1 |
127 end; |
117 end; |
128 |
118 |
129 (* ------------------------------------------------------------------------- *) |
119 (* ------------------------------------------------------------------------- *) |
130 (* Substitutions can be inverted iff they are renaming substitutions. *) |
120 (* Creating the union of two compatible substitutions. *) |
|
121 (* ------------------------------------------------------------------------- *) |
|
122 |
|
123 local |
|
124 fun compatible ((_,tm1),(_,tm2)) = |
|
125 if Term.equal tm1 tm2 then SOME tm1 |
|
126 else raise Error "Subst.union: incompatible"; |
|
127 in |
|
128 fun union (s1 as Subst m1) (s2 as Subst m2) = |
|
129 if NameMap.null m1 then s2 |
|
130 else if NameMap.null m2 then s1 |
|
131 else Subst (NameMap.union compatible m1 m2); |
|
132 end; |
|
133 |
|
134 (* ------------------------------------------------------------------------- *) |
|
135 (* Substitutions can be inverted iff they are renaming substitutions. *) |
131 (* ------------------------------------------------------------------------- *) |
136 (* ------------------------------------------------------------------------- *) |
132 |
137 |
133 local |
138 local |
134 fun inv (v, Term.Var w, s) = |
139 fun inv (v, Term.Var w, s) = |
135 if NameMap.inDomain w s then raise Error "Subst.invert: non-injective" |
140 if NameMap.inDomain w s then raise Error "Subst.invert: non-injective" |
148 val freshVars = |
153 val freshVars = |
149 let |
154 let |
150 fun add (v,m) = insert m (v, Term.newVar ()) |
155 fun add (v,m) = insert m (v, Term.newVar ()) |
151 in |
156 in |
152 NameSet.foldl add empty |
157 NameSet.foldl add empty |
|
158 end; |
|
159 |
|
160 (* ------------------------------------------------------------------------- *) |
|
161 (* Free variables. *) |
|
162 (* ------------------------------------------------------------------------- *) |
|
163 |
|
164 val redexes = |
|
165 let |
|
166 fun add (v,_,s) = NameSet.add s v |
|
167 in |
|
168 foldl add NameSet.empty |
|
169 end; |
|
170 |
|
171 val residueFreeVars = |
|
172 let |
|
173 fun add (_,t,s) = NameSet.union s (Term.freeVars t) |
|
174 in |
|
175 foldl add NameSet.empty |
|
176 end; |
|
177 |
|
178 val freeVars = |
|
179 let |
|
180 fun add (v,t,s) = NameSet.union (NameSet.add s v) (Term.freeVars t) |
|
181 in |
|
182 foldl add NameSet.empty |
|
183 end; |
|
184 |
|
185 (* ------------------------------------------------------------------------- *) |
|
186 (* Functions. *) |
|
187 (* ------------------------------------------------------------------------- *) |
|
188 |
|
189 val functions = |
|
190 let |
|
191 fun add (_,t,s) = NameAritySet.union s (Term.functions t) |
|
192 in |
|
193 foldl add NameAritySet.empty |
153 end; |
194 end; |
154 |
195 |
155 (* ------------------------------------------------------------------------- *) |
196 (* ------------------------------------------------------------------------- *) |
156 (* Matching for first order logic terms. *) |
197 (* Matching for first order logic terms. *) |
157 (* ------------------------------------------------------------------------- *) |
198 (* ------------------------------------------------------------------------- *) |
162 let |
203 let |
163 val sub = |
204 val sub = |
164 case peek sub v of |
205 case peek sub v of |
165 NONE => insert sub (v,tm) |
206 NONE => insert sub (v,tm) |
166 | SOME tm' => |
207 | SOME tm' => |
167 if tm = tm' then sub |
208 if Term.equal tm tm' then sub |
168 else raise Error "Subst.match: incompatible matches" |
209 else raise Error "Subst.match: incompatible matches" |
169 in |
210 in |
170 matchList sub rest |
211 matchList sub rest |
171 end |
212 end |
172 | matchList sub ((Term.Fn (f1,args1), Term.Fn (f2,args2)) :: rest) = |
213 | matchList sub ((Term.Fn (f1,args1), Term.Fn (f2,args2)) :: rest) = |
173 if f1 = f2 andalso length args1 = length args2 then |
214 if Name.equal f1 f2 andalso length args1 = length args2 then |
174 matchList sub (zip args1 args2 @ rest) |
215 matchList sub (zip args1 args2 @ rest) |
175 else raise Error "Subst.match: different structure" |
216 else raise Error "Subst.match: different structure" |
176 | matchList _ _ = raise Error "Subst.match: functions can't match vars"; |
217 | matchList _ _ = raise Error "Subst.match: functions can't match vars"; |
177 in |
218 in |
178 fun match sub tm1 tm2 = matchList sub [(tm1,tm2)]; |
219 fun match sub tm1 tm2 = matchList sub [(tm1,tm2)]; |
195 (case peek sub v of |
236 (case peek sub v of |
196 NONE => solve (compose sub (singleton (v,tm))) rest |
237 NONE => solve (compose sub (singleton (v,tm))) rest |
197 | SOME tm' => solve' sub tm' tm rest) |
238 | SOME tm' => solve' sub tm' tm rest) |
198 | solve' sub tm1 (tm2 as Term.Var _) rest = solve' sub tm2 tm1 rest |
239 | solve' sub tm1 (tm2 as Term.Var _) rest = solve' sub tm2 tm1 rest |
199 | solve' sub (Term.Fn (f1,args1)) (Term.Fn (f2,args2)) rest = |
240 | solve' sub (Term.Fn (f1,args1)) (Term.Fn (f2,args2)) rest = |
200 if f1 = f2 andalso length args1 = length args2 then |
241 if Name.equal f1 f2 andalso length args1 = length args2 then |
201 solve sub (zip args1 args2 @ rest) |
242 solve sub (zip args1 args2 @ rest) |
202 else |
243 else |
203 raise Error "Subst.unify: different structure"; |
244 raise Error "Subst.unify: different structure"; |
204 in |
245 in |
205 fun unify sub tm1 tm2 = solve sub [(tm1,tm2)]; |
246 fun unify sub tm1 tm2 = solve sub [(tm1,tm2)]; |