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
134 | L t1 -> subst 0 true (0, t2) t1
\r
139 | V m -> V (if m >= lev then m + n else m)
\r
140 | L t -> L (aux (lev+1) t)
\r
141 | A (t1, t2) -> A (aux lev t1, aux lev t2)
\r
146 let subst = subst 0 false;;
\r
148 let subst_in_problem sub p =
\r
149 print_endline ("-- SUBST " ^ string_of_t (V (fst sub)) ^ " |-> " ^ string_of_t (snd sub));
\r
151 div=subst sub p.div;
\r
152 conv=subst sub p.conv;
\r
153 stepped=(fst sub)::p.stepped;
\r
154 sigma=sub::p.sigma}
\r
157 let get_subterm_with_head_and_args hd_var n_args =
\r
158 let rec aux lev = function
\r
161 | L t -> aux (lev+1) t
\r
163 let hd_var', n_args' = get_inert t1 in
\r
164 if hd_var' = hd_var + lev && n_args <= 1 + n_args'
\r
165 then Some (lift ~-lev t)
\r
166 else match aux lev t2 with
\r
167 | None -> aux lev t1
\r
168 | Some _ as res -> res
\r
172 let rec purify = function
\r
173 | L t -> Pure.L (purify t)
\r
174 | A (t1,t2) -> Pure.A (purify t1, purify t2)
\r
176 | C _ -> Pure.V max_int (* FIXME *)
\r
180 let check p sigma =
\r
181 print_endline "Checking...";
\r
182 let div = purify p.div in
\r
183 let conv = purify p.conv in
\r
184 let sigma = List.map (fun (v,t) -> v, purify t) sigma in
\r
185 let freshno = List.fold_right (fun (x,_) -> max x) sigma 0 in
\r
186 let env = Pure.env_of_sigma freshno sigma in
\r
187 assert (Pure.diverged (Pure.mwhd (env,div,[])));
\r
188 print_endline " D diverged.";
\r
189 assert (not (Pure.diverged (Pure.mwhd (env,conv,[]))));
\r
190 print_endline " C converged.";
\r
195 print_endline (string_of_problem p); (* non cancellare *)
\r
196 if p.conv = B then problem_fail p "p.conv diverged";
\r
197 if p.div = B then raise (Done p.sigma);
\r
198 if p.phase = `Two && p.div = delta then raise (Done p.sigma);
\r
199 if not (is_inert p.div) then problem_fail p "p.div converged";
\r
203 (* drops the arguments of t after the n-th *)
\r
204 let inert_cut_at n t =
\r
209 let k', t' = aux t1 in
\r
210 if k' = n then n, t'
\r
212 | _ -> assert false
\r
216 let find_eta_difference p t n_args =
\r
217 let t = inert_cut_at n_args t in
\r
218 let rec aux t u k = match t, u with
\r
219 | V _, V _ -> assert false (* div subterm of conv *)
\r
220 | A(t1,t2), A(u1,u2) ->
\r
221 if not (eta_eq t2 u2) then ((*print_endline((string_of_t t2) ^ " <> " ^ (string_of_t u2));*) k)
\r
222 else aux t1 u1 (k-1)
\r
223 | _, _ -> assert false
\r
224 in aux p.div t n_args
\r
227 let compute_max_lambdas_at hd_var j =
\r
228 let rec aux hd = function
\r
230 (if get_inert t1 = (hd, j)
\r
231 then max ( (*FIXME*)
\r
232 if is_inert t2 && let hd', j' = get_inert t2 in hd' = hd
\r
233 then let hd', j' = get_inert t2 in j - j'
\r
234 else no_leading_lambdas hd_var j t2)
\r
235 else id) (max (aux hd t1) (aux hd t2))
\r
236 | L t -> aux (hd+1) t
\r
238 | _ -> assert false
\r
242 let print_cmd s1 s2 = print_endline (">> " ^ s1 ^ " " ^ s2);;
\r
244 (* eat the arguments of the divergent and explode.
\r
245 It does NOT perform any check, may fail if done unsafely *)
\r
247 print_cmd "EAT" "";
\r
248 let var, k = get_inert p.div in
\r
249 let phase = p.phase in
\r
254 (compute_max_lambdas_at var k p.div)
\r
255 (compute_max_lambdas_at var k p.conv) in
\r
256 (* apply fresh vars *)
\r
257 let p, t = fold_nat (fun (p, t) _ ->
\r
258 let p, v = freshvar p in
\r
261 let p = {p with phase=`Two} in p, A(t, delta)
\r
262 | `Two -> p, delta in
\r
263 let subst = var, mk_lams t k in
\r
264 let p = subst_in_problem subst p in
\r
266 let p = if phase = `One then {p with div = (match p.div with A(t,_) -> t | _ -> assert false)} else p in
\r
270 (* step on the head of div, on the k-th argument, with n fresh vars *)
\r
272 let var, _ = get_inert p.div in
\r
273 print_cmd "STEP" ("on " ^ string_of_t (V var) ^ " (of:" ^ string_of_int n ^ ")");
\r
274 let p, t = (* apply fresh vars *)
\r
275 fold_nat (fun (p, t) _ ->
\r
276 let p, v = freshvar p in
\r
277 p, A(t, V (v + k + 1))
\r
279 let t = (* apply unused bound variables V_{k-1}..V_1 *)
\r
280 fold_nat (fun t m -> A(t, V (k-m+1))) t k in
\r
281 let t = mk_lams t (k+1) in (* make leading lambdas *)
\r
282 let subst = var, t in
\r
283 let p = subst_in_problem subst p in
\r
289 let rec aux level = function
\r
290 | Parser_andrea.Lam t -> L (aux (level + 1) t)
\r
291 | Parser_andrea.App (t1, t2) ->
\r
292 if level = 0 then mk_app (aux level t1) (aux level t2)
\r
293 else A(aux level t1, aux level t2)
\r
294 | Parser_andrea.Var v -> V v in
\r
295 let (tms, free) = Parser_andrea.parse_many strs in
\r
296 (List.map (aux 0) tms, free)
\r
300 let hd_var, n_args = get_inert p.div in
\r
301 match get_subterm_with_head_and_args hd_var n_args p.conv with
\r
304 let phase = p.phase in
\r
307 then problem_fail p "Auto.2 did not complete the problem"
\r
309 with Done sigma -> sigma)
\r
311 let j = find_eta_difference p t n_args - 1 in
\r
313 (compute_max_lambdas_at hd_var j p.div)
\r
314 (compute_max_lambdas_at hd_var j p.conv) in
\r
315 let p = step j k p in
\r
319 let problem_of div convs =
\r
320 let rec conv_join = function
\r
322 | x::xs -> conv_join xs ^ " ("^ x ^")" in
\r
324 let conv = conv_join convs in
\r
325 let [@warning "-8"] [div; conv], var_names = parse ([div; conv]) in
\r
326 let varno = List.length var_names in
\r
327 let p = {orig_freshno=varno; freshno=1+varno; div; conv; sigma=[]; stepped=[]; phase=`One} in
\r
328 (* initial sanity check *)
\r
333 if eta_subterm p.div p.conv
\r
334 then print_endline "!!! div is subterm of conv. Problem was not run !!!"
\r
335 else check p (auto p)
\r
338 let run x y = solve (problem_of x y);;
\r
340 (* Example usage of interactive: *)
\r
342 (* let interactive div conv cmds =
\r
343 let p = problem_of div conv in
\r
345 let p = List.fold_left (|>) p cmds in
\r
347 let nth spl n = int_of_string (List.nth spl n) in
\r
349 let s = read_line () in
\r
350 let spl = Str.split (Str.regexp " +") s in
\r
351 s, let uno = List.hd spl in
\r
352 try if uno = "eat" then eat
\r
353 else if uno = "step" then step (nth spl 1) (nth spl 2)
\r
354 else failwith "Wrong input."
\r
355 with Failure s -> print_endline s; (fun x -> x) in
\r
356 let str, cmd = read_cmd () in
\r
357 let cmds = (" " ^ str ^ ";")::cmds in
\r
359 let p = cmd p in f p cmds
\r
361 | Done _ -> print_endline "Done! Commands history: "; List.iter print_endline (List.rev cmds)
\r
363 ) with Done _ -> ()
\r
366 (* interactive "x y"
\r
367 "@ (x x) (y x) (y z)" [step 0 1; step 0 2; eat]
\r
370 run "x x" ["x y"; "y y"; "y x"] ;;
\r
371 run "x y" ["x (_. x)"; "y z"; "y x"] ;;
\r
372 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
374 run "x (y. x y y)" ["x (y. x y x)"] ;;
\r
383 (* Controesempio ad usare un conto dei lambda che non considere le permutazioni *)
\r
384 run "x a a a a (x (x. x x) @ @ (_._.x. x x) x) b b b" [
\r
385 "x a a a a (_. a) b b b";
\r
386 "x a a a a (_. _. _. _. x. y. x y)";
\r
389 (* bug in no_leading_lambdas where x in j-th position *)
\r
390 run "v0 (v1 v2) (x. y. v0 v3 v4 v2)"
\r
391 ["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
395 print_endline ">>> EXAMPLES IN simple.ml FINISHED <<<"
\r