1 let (++) f g x = f (g x);;
\r
3 let rec fold_nat f x n = if n = 0 then x else f (fold_nat f x (n-1)) n ;;
\r
5 let print_hline = Console.print_hline;;
\r
18 let delta = L(A(V 0, V 0));;
\r
21 let rec aux l1 l2 t1 t2 = match t1, t2 with
\r
22 | L t1, L t2 -> aux l1 l2 t1 t2
\r
23 | L t1, t2 -> aux l1 (l2+1) t1 t2
\r
24 | t1, L t2 -> aux (l1+1) l2 t1 t2
\r
25 | V a, V b -> a + l1 = b + l2
\r
27 | A(t1,t2), A(u1,u2) -> aux l1 l2 t1 u1 && aux l1 l2 t2 u2
\r
30 let eta_eq = eta_eq' 0 0;;
\r
32 (* is arg1 eta-subterm of arg2 ? *)
\r
34 let rec aux lev t = eta_eq' lev 0 u t || match t with
\r
35 | L t -> aux (lev+1) t
\r
36 | A(t1, t2) -> aux lev t1 || aux lev t2
\r
41 (* does NOT lift the argument *)
\r
42 let mk_lams = fold_nat (fun x _ -> L x) ;;
\r
45 let string_of_bvar =
\r
46 let bound_vars = ["x"; "y"; "z"; "w"; "q"] in
\r
47 let bvarsno = List.length bound_vars in
\r
48 fun nn -> if nn < bvarsno then List.nth bound_vars nn else "x" ^ (string_of_int (nn - bvarsno + 1)) in
\r
49 let rec string_of_term_w_pars level = function
\r
50 | V v -> if v >= level then "`" ^ string_of_int (v-level) else
\r
51 string_of_bvar (level - v-1)
\r
52 | C n -> "c" ^ string_of_int n
\r
54 | L _ as t -> "(" ^ string_of_term_no_pars level t ^ ")"
\r
56 and string_of_term_no_pars_app level = function
\r
57 | A(t1,t2) -> string_of_term_no_pars_app level t1 ^ " " ^ string_of_term_w_pars level t2
\r
58 | _ as t -> string_of_term_w_pars level t
\r
59 and string_of_term_no_pars level = function
\r
60 | L t -> "λ" ^ string_of_bvar level ^ ". " ^ string_of_term_no_pars (level+1) t
\r
61 | _ as t -> string_of_term_no_pars_app level t
\r
62 in string_of_term_no_pars 0
\r
70 ; sigma : (var * t) list (* substitutions *)
\r
71 ; stepped : var list
\r
72 ; phase : [`One | `Two] (* :'( *)
\r
75 let string_of_problem p =
\r
77 "[stepped] " ^ String.concat " " (List.map string_of_int p.stepped);
\r
78 "[DV] " ^ string_of_t p.div;
\r
79 "[CV] " ^ string_of_t p.conv;
\r
81 String.concat "\n" lines
\r
84 exception Done of (var * t) list (* substitution *);;
\r
85 exception Fail of int * string;;
\r
87 let problem_fail p reason =
\r
88 print_endline "!!!!!!!!!!!!!!! FAIL !!!!!!!!!!!!!!!";
\r
89 print_endline (string_of_problem p);
\r
90 raise (Fail (-1, reason))
\r
93 let freshvar ({freshno} as p) =
\r
94 {p with freshno=freshno+1}, freshno+1
\r
99 | A(t,_) -> is_inert t
\r
105 let is_var = function V _ -> true | _ -> false;;
\r
106 let is_lambda = function L _ -> true | _ -> false;;
\r
108 let rec get_inert = function
\r
110 | A(t, _) -> let hd,args = get_inert t in hd,args+1
\r
111 | _ -> assert false
\r
114 let rec no_leading_lambdas hd_var j = function
\r
115 | L t -> 1 + no_leading_lambdas (hd_var+1) j t
\r
116 | A _ as t -> let hd_var', n = get_inert t in if hd_var = hd_var' then max 0 (j - n) else 0
\r
117 | V n -> if n = hd_var then j else 0
\r
120 let rec subst level delift sub =
\r
122 | V v -> if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v)
\r
123 | L t -> let t = subst (level + 1) delift sub t in if t = B then B else L t
\r
125 let t1 = subst level delift sub t1 in
\r
126 let t2 = subst level delift sub t2 in
\r
130 and mk_app t1 t2 = if t2 = B || (t1 = delta && t2 = delta) then B
\r
133 | L t1 -> subst 0 true (0, t2) t1
\r
138 | V m -> V (if m >= lev then m + n else m)
\r
139 | L t -> L (aux (lev+1) t)
\r
140 | A (t1, t2) -> A (aux lev t1, aux lev t2)
\r
145 let subst = subst 0 false;;
\r
147 let subst_in_problem sub p =
\r
148 print_endline ("-- SUBST " ^ string_of_t (V (fst sub)) ^ " |-> " ^ string_of_t (snd sub));
\r
150 div=subst sub p.div;
\r
151 conv=subst sub p.conv;
\r
152 stepped=(fst sub)::p.stepped;
\r
153 sigma=sub::p.sigma}
\r
156 let get_subterm_with_head_and_args hd_var n_args =
\r
157 let rec aux lev = function
\r
160 | L t -> aux (lev+1) t
\r
162 let hd_var', n_args' = get_inert t1 in
\r
163 if hd_var' = hd_var + lev && n_args <= 1 + n_args'
\r
164 then Some (lift ~-lev t)
\r
165 else match aux lev t2 with
\r
166 | None -> aux lev t1
\r
167 | Some _ as res -> res
\r
171 let rec purify = function
\r
172 | L t -> Pure.L (purify t)
\r
173 | A (t1,t2) -> Pure.A (purify t1, purify t2)
\r
175 | C _ -> Pure.V max_int (* FIXME *)
\r
179 let check p sigma =
\r
180 print_endline "Checking...";
\r
181 let div = purify p.div in
\r
182 let conv = purify p.conv in
\r
183 let sigma = List.map (fun (v,t) -> v, purify t) sigma in
\r
184 let freshno = List.fold_right (fun (x,_) -> max x) sigma 0 in
\r
185 let env = Pure.env_of_sigma freshno sigma in
\r
186 assert (Pure.diverged (Pure.mwhd (env,div,[])));
\r
187 print_endline " D diverged.";
\r
188 assert (not (Pure.diverged (Pure.mwhd (env,conv,[]))));
\r
189 print_endline " C converged.";
\r
194 print_endline (string_of_problem p); (* non cancellare *)
\r
195 if p.conv = B then problem_fail p "p.conv diverged";
\r
196 if p.div = B then raise (Done p.sigma);
\r
197 if p.phase = `Two && p.div = delta then raise (Done p.sigma);
\r
198 if not (is_inert p.div) then problem_fail p "p.div converged";
\r
202 (* drops the arguments of t after the n-th *)
\r
203 let inert_cut_at n t =
\r
208 let k', t' = aux t1 in
\r
209 if k' = n then n, t'
\r
211 | _ -> assert false
\r
215 let find_eta_difference p t n_args =
\r
216 let t = inert_cut_at n_args t in
\r
217 let rec aux t u k = match t, u with
\r
218 | V _, V _ -> assert false (* div subterm of conv *)
\r
219 | A(t1,t2), A(u1,u2) ->
\r
220 if not (eta_eq t2 u2) then ((*print_endline((string_of_t t2) ^ " <> " ^ (string_of_t u2));*) k)
\r
221 else aux t1 u1 (k-1)
\r
222 | _, _ -> assert false
\r
223 in aux p.div t n_args
\r
226 let compute_max_lambdas_at hd_var j =
\r
227 let rec aux hd = function
\r
229 (if get_inert t1 = (hd, j)
\r
230 then max ( (*FIXME*)
\r
231 if is_inert t2 && let hd', j' = get_inert t2 in hd' = hd
\r
232 then let hd', j' = get_inert t2 in j - j'
\r
233 else no_leading_lambdas hd_var j t2)
\r
234 else id) (max (aux hd t1) (aux hd t2))
\r
235 | L t -> aux (hd+1) t
\r
237 | _ -> assert false
\r
241 let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;
\r
243 (* eat the arguments of the divergent and explode.
\r
244 It does NOT perform any check, may fail if done unsafely *)
\r
246 print_cmd "EAT" "";
\r
247 let var, k = get_inert p.div in
\r
248 let phase = p.phase in
\r
253 (compute_max_lambdas_at var (k-1) p.div)
\r
254 (compute_max_lambdas_at var (k-1) p.conv) in
\r
255 (* apply fresh vars *)
\r
256 let p, t = fold_nat (fun (p, t) _ ->
\r
257 let p, v = freshvar p in
\r
260 let p = {p with phase=`Two} in
\r
261 let t = A(t, delta) in
\r
262 let t = fold_nat (fun t m -> A(t, V (k-m))) t (k-1) in
\r
263 let subst = var, mk_lams t k in
\r
264 let p = subst_in_problem subst p in
\r
265 let _, args = get_inert p.div in
\r
266 {p with div = inert_cut_at (args-k) p.div}
\r
268 let subst = var, mk_lams delta k in
\r
269 subst_in_problem subst p in
\r
273 (* step on the head of div, on the k-th argument, with n fresh vars *)
\r
275 let var, _ = get_inert p.div in
\r
276 print_cmd "STEP" ("on " ^ string_of_t (V var) ^ " (of:" ^ string_of_int n ^ ")");
\r
277 let p, t = (* apply fresh vars *)
\r
278 fold_nat (fun (p, t) _ ->
\r
279 let p, v = freshvar p in
\r
280 p, A(t, V (v + k + 1))
\r
282 let t = (* apply unused bound variables V_{k-1}..V_1 *)
\r
283 fold_nat (fun t m -> A(t, V (k-m+1))) t k in
\r
284 let t = mk_lams t (k+1) in (* make leading lambdas *)
\r
285 let subst = var, t in
\r
286 let p = subst_in_problem subst p in
\r
292 let rec aux level = function
\r
293 | Parser_andrea.Lam t -> L (aux (level + 1) t)
\r
294 | Parser_andrea.App (t1, t2) ->
\r
295 if level = 0 then mk_app (aux level t1) (aux level t2)
\r
296 else A(aux level t1, aux level t2)
\r
297 | Parser_andrea.Var v -> V v in
\r
298 let (tms, free) = Parser_andrea.parse_many strs in
\r
299 (List.map (aux 0) tms, free)
\r
303 let hd_var, n_args = get_inert p.div in
\r
304 match get_subterm_with_head_and_args hd_var n_args p.conv with
\r
307 let phase = p.phase in
\r
310 then problem_fail p "Auto.2 did not complete the problem"
\r
312 with Done sigma -> sigma)
\r
314 let j = find_eta_difference p t n_args - 1 in
\r
316 (compute_max_lambdas_at hd_var j p.div)
\r
317 (compute_max_lambdas_at hd_var j p.conv) in
\r
318 let p = step j k p in
\r
322 let problem_of div convs =
\r
323 let rec conv_join = function
\r
325 | x::xs -> conv_join xs ^ " ("^ x ^")" in
\r
327 let conv = conv_join convs in
\r
328 let [@warning "-8"] [div; conv], var_names = parse ([div; conv]) in
\r
329 let varno = List.length var_names in
\r
330 let p = {orig_freshno=varno; freshno=1+varno; div; conv; sigma=[]; stepped=[]; phase=`One} in
\r
331 (* initial sanity check *)
\r
336 if eta_subterm p.div p.conv
\r
337 then print_endline "!!! div is subterm of conv. Problem was not run !!!"
\r
338 else check p (auto p)
\r
341 let run x y = solve (problem_of x y);;
\r
343 (* Example usage of interactive: *)
\r
345 (* let interactive div conv cmds =
\r
346 let p = problem_of div conv in
\r
348 let p = List.fold_left (|>) p cmds in
\r
350 let nth spl n = int_of_string (List.nth spl n) in
\r
352 let s = read_line () in
\r
353 let spl = Str.split (Str.regexp " +") s in
\r
354 s, let uno = List.hd spl in
\r
355 try if uno = "eat" then eat
\r
356 else if uno = "step" then step (nth spl 1) (nth spl 2)
\r
357 else failwith "Wrong input."
\r
358 with Failure s -> print_endline s; (fun x -> x) in
\r
359 let str, cmd = read_cmd () in
\r
360 let cmds = (" " ^ str ^ ";")::cmds in
\r
362 let p = cmd p in f p cmds
\r
364 | Done _ -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)
\r
366 ) with Done _ -> ()
\r
369 (* interactive "x y"
\r
370 "@ (x x) (y x) (y z)" [step 0 1; step 0 2; eat]
\r
373 run "x x" ["x y"; "y y"; "y x"] ;;
\r
374 run "x y" ["x (_. x)"; "y z"; "y x"] ;;
\r
375 run "a (x. x b) (x. x c)" ["a (x. b b) @"; "a @ c"; "a (x. x x) a"; "a (a a a) (a c c)"] ;;
\r
377 run "x (y. x y y)" ["x (y. x y x)"] ;;
\r
386 (* Controesempio ad usare un conto dei lambda che non considere le permutazioni *)
\r
387 run "x a a a a (x (x. x x) @ @ (_._.x. x x) x) b b b" [
\r
388 "x a a a a (_. a) b b b";
\r
389 "x a a a a (_. _. _. _. x. y. x y)";
\r
392 (* bug in eat that was erasing terms in convergent that then diverged *)
\r
399 (* bug in no_leading_lambdas where x in j-th position *)
\r
400 run "v0 (v1 v2) (x. y. v0 v3 v4 v2)"
\r
401 ["v5 (v6 (x. v6) v7 v8 (x. v9) (x. v9 (v10 v10))) (v6 (x. v6) v7 v8 (v9 (x. v11) (v4 v8) (x. y. z. v12)) (v13 (x. y. y))) (v9 (x. v11) (v4 v8) (x. y. z. v12) (v4 v6 (x. v7 v11) v12) (x. x v8)) (v0 v3 v4 v9 (v7 v11) (v0 v3 v4 v2) v10) (v6 (x. v6) v7 v8 (v9 (x. v11) (v4 v8) (x. y. z. v12)) (v13 (x. y. y)) (v9 (x. v11) (v4 v8)))"]
\r
405 print_endline ">>> EXAMPLES IN simple.ml FINISHED <<<"
\r