1 let print_hline = Console.print_hline;;
\r
10 t list (* body of the match *)
\r
11 * int (* explicit liftno *)
\r
12 * int (* variable which originated this match (id) *)
\r
22 ; matches : (var (* variable originating this match *) * (t (* term to discriminate *) * t (* continuation *)) list) list
\r
23 ; sigma : (var * t) list (* substitutions *)
\r
27 let bound_vars = ["x"; "y"; "z"; "z1"; "z2"] in
\r
28 let rec aux level = function
\r
29 | V v -> if v >= level then "`" ^ string_of_int (v-level) else List.nth bound_vars (level - v-1)
\r
30 | A (t1,t2) -> "("^aux level t1^" "^aux level t2^")"
\r
31 | L t -> "(\\" ^ aux (level+1) (V 0) ^ ". " ^ aux (level+1) t ^ ")"
\r
32 | LM (ts,liftno,id) -> "[match orig="^aux 0 (V id)^"]"
\r
38 let string_of_problem p =
\r
40 "[DV] " ^ string_of_t p p.div;
\r
41 "[CV] " ^ String.concat "\n " (List.map (string_of_t p) p.conv);
\r
43 ] @ Util.concat_map (fun (_, lst) -> "[<>]" :: List.map (fun (t,c) -> " " ^ string_of_t p t
\r
44 (* ^" -> " ^ string_of_t p c *)
\r
45 ) lst) p.matches @ [""] in
\r
46 String.concat "\n" lines
\r
49 let problem_fail p reason =
\r
50 print_endline " FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL";
\r
51 print_endline (string_of_problem p);
\r
55 let freshvar ({freshno} as p) =
\r
56 {p with freshno=freshno+1}, freshno+1
\r
59 let add_to_match p id entry =
\r
61 let _ = List.assoc id p.matches in
\r
62 List.map (fun (id',lst as x) -> if id <> id' then x else (id, entry::lst) ) p.matches
\r
64 | Not_found -> (id,[entry]) :: p.matches in
\r
65 {p with matches=matches}
\r
69 let rec aux level = function
\r
70 | V v' -> v + level = v'
\r
71 | A(t1,t2) -> (aux level t1) || (aux level t2)
\r
72 | L t -> aux (level+1) t
\r
73 | LM(ts,_,_) -> List.fold_left (fun a b -> a || aux (level+1) b) false ts
\r
81 | A(t,_) -> is_inert t
\r
82 | L _ | LM _ | B -> false
\r
86 let is_var = function V _ -> true | _ -> false;;
\r
87 let is_lambda = function L _ -> true | _ -> false;;
\r
88 let is_pacman = function P -> true | _ -> false;;
\r
90 let rec subst level delift sub p =
\r
92 | V v -> p, if v = level + fst sub then lift level (snd sub) else V (if delift && v > level then v-1 else v)
\r
93 | L t -> let p, t = subst (level + 1) delift sub p t in p, L t
\r
95 let p, t1 = subst level delift sub p t1 in
\r
96 let p, t2 = subst level delift sub p t2 in
\r
97 if t1 = B || t2 = B then p, B else
\r
98 if level = 0 then mk_app p t1 t2 else p, A (t1, t2)
\r
99 | LM (ts, liftno, id) ->
\r
101 let rec aux p = function
\r
104 let p, ts = aux p ts in
\r
105 let p, t = subst (level+1) delift sub p t in
\r
108 p, LM(ts, liftno, id)
\r
111 and mk_app p t1 t2 = let t1 = if t1 = P then L P else t1 in match t1 with
\r
113 let p = if is_inert t2 && not (is_var t2) && free_in 0 t1 then {p with conv=t2::p.conv} else p in
\r
114 subst 0 true (0, t2) p t1
\r
115 | LM(ts,liftno,id) ->
\r
116 let p, t = mk_apps p t2 (List.map (lift ~-1) ts) in
\r
120 let p, cont = freshvar p in
\r
121 let newvar = V cont in
\r
122 let p = add_to_match p id (t,newvar) in
\r
125 | _ when t2 = B -> p, B
\r
126 | t1 -> p, A (t1, t2)
\r
130 | t'::ts -> let p, t = mk_app p t t' in mk_apps p t ts
\r
131 and lift n = function
\r
133 | L t -> L (lift n t)
\r
134 | A (t1, t2) -> A (lift n t1, lift n t2)
\r
135 | LM (ts, liftno, id) -> LM (List.map (lift n) ts, n + liftno, id)
\r
140 let subst = subst 0 false;;
\r
142 let mk_lambda t = L (lift 1 t) ;;
\r
144 let subst_many sub =
\r
145 let rec aux p = function
\r
148 let p, t = subst sub p t in
\r
149 let p, tms = aux p tms in
\r
154 let rec subst_in_matches sub p =
\r
157 | (v, branches) :: ms->
\r
158 let a, b = List.split branches in
\r
159 let p, a = subst_many sub p a in
\r
160 let p, b = subst_many sub p b in
\r
161 let branches = List.combine a b in
\r
162 let p, ms = subst_in_matches sub p ms in
\r
163 p, (v, branches) :: ms
\r
166 let subst_in_problem (sub: var * t) (p: problem) =
\r
167 (* print_endline ("SUBST IN PROBLEM: " ^ string_of_t p (V (fst sub)) ^ " " ^ string_of_t p (snd sub)); *)
\r
168 let p', div = subst sub p p.div in
\r
169 let p = {p' with conv=p.conv} in
\r
170 let p, conv = subst_many sub p p.conv in
\r
171 let p, matches = subst_in_matches sub p p.matches in
\r
172 {p with div=div; conv=conv; matches=matches; sigma=sub::p.sigma}
\r
176 let unify_terms p t1 t2 =
\r
178 | V v -> subst_in_problem (v, t2) p
\r
179 | _ -> problem_fail p "The collapse of a match came after too many steps :(";;
\r
182 let rec give_duplicates =
\r
183 let rec aux' t = function
\r
185 | (t',c')::ts -> if t = t' then ts, Some c' else (
\r
186 let ts, res = aux' t ts in (t',c')::ts, res) in
\r
187 let rec aux = function
\r
190 match aux' t rest with
\r
191 | rest, None -> aux rest
\r
192 | rest, Some c' -> (t,c)::rest, Some (c', c)
\r
196 | (orig,branches) :: ms ->
\r
197 match aux branches with
\r
198 | _, None -> let ms, res = give_duplicates ms in (orig,branches) :: ms, res
\r
199 | branches', Some subst -> (orig,branches') :: ms, Some subst in
\r
200 let matches, vars_to_be_unified = give_duplicates p.matches in
\r
201 let p = {p with matches=matches} in
\r
202 match vars_to_be_unified with
\r
205 (* print_endline ("> unify " ^ string_of_t p (t') ^ " with " ^ string_of_t p t); *)
\r
206 unify (unify_terms p t' t)
\r
209 let problem_done p =
\r
210 let all_separated = List.for_all (fun (_, lst) -> List.length lst = 1 || List.for_all (fun (t,_) -> is_var t) lst) p.matches in
\r
211 all_separated && p.div = B
\r
217 (* Sanity checks: *)
\r
218 if is_lambda p.div || is_pacman p.div then problem_fail p "p.div converged" ;
\r
219 List.iter (function | B -> problem_fail p "p.conv diverged" | _ -> ()) p.conv;
\r
220 if not (List.for_all (fun (_, lst) -> List.for_all (fun (t,_) -> is_inert t) lst) p.matches)
\r
221 then problem_fail p "Lambda in a match: k was not big enough?";
\r
223 (* Remove lambdas from conv TODO remove duplicates *)
\r
224 let conv = List.filter is_inert p.conv in
\r
225 let p = {p with conv=conv} in
\r
228 print_endline (string_of_problem p);
\r
229 if problem_done p then raise Done else p
\r
232 let ignore var n p =
\r
234 "--- EAT on " ^ string_of_t p (V var)
\r
235 ^ " (of:" ^ string_of_int n ^ ")");
\r
239 else L (aux (m-1) t) in
\r
240 let subst = var, aux n (V var) in
\r
241 sanity (subst_in_problem subst p)
\r
244 let explode' var p =
\r
246 "--- EXPLODE on " ^ string_of_t p (V var)
\r
248 let subst = var, B in
\r
249 sanity (subst_in_problem subst p)
\r
254 | V var -> explode' var p
\r
255 | _ -> problem_fail p "premature explosion"
\r
260 "--- STEP on " ^ string_of_t p (V var));
\r
261 let subst = var, LM([], 0, var) in
\r
262 sanity (subst_in_problem subst p)
\r
267 "--- ID on " ^ string_of_t p (V var));
\r
268 let subst = var, L(V 0) in
\r
269 sanity (subst_in_problem subst p)
\r
272 let apply var appk p =
\r
274 "--- APPLY_CONSTS on " ^ string_of_t p (V var)
\r
275 ^ " (special_k:" ^ string_of_int appk ^ ")");
\r
276 let rec mk_freshvars n p =
\r
280 let p, vs = mk_freshvars (n-1) p in
\r
281 let p, v = freshvar p in
\r
283 let p, vars = mk_freshvars appk p in
\r
284 let p, t = mk_apps p (V 0) (List.map (lift 1) vars) in
\r
285 let t = L (A (lift 1 (V var), t)) in
\r
286 let subst = var, t in
\r
287 sanity (subst_in_problem subst p)
\r
292 "--- PERM on " ^ string_of_t p (V var)
\r
293 ^ " (of:" ^ string_of_int n ^ ")");
\r
294 (* let p, v = freshvar p in *)
\r
295 let rec aux' m t = if m < 0 then t else A(aux' (m-1) t, V m) in
\r
299 else L (aux (m-1) t) in
\r
300 let t = aux n (lift n (V var)) in
\r
301 let subst = var, t in
\r
302 sanity (subst_in_problem subst p)
\r
306 - cosi' come e' possibile unificare rami di branch solo se vanno -> a variabili,
\r
307 allo stesso modo e' possibile ignorare dei rami se vanno in variabili, e quelle variabili
\r
308 vengono sostituite ovunque: con bombe in conv e con pacman in div
\r
310 (* let forget var n p =
\r
311 let remove_from_branch p var n = ... in
\r
312 let p, (tm, c) = remove_from_branch p var n in
\r
314 "--- FORGET " ^ string_of_t p tm ^ " from the match of " ^ string_of_t p (V var)
\r
315 ^ " (of:" ^ string_of_int n ^ ")");
\r
320 let dummy_p = {freshno=0; div=V 0; conv=[]; matches=[]; sigma=[]} in
\r
321 let rec aux level = function
\r
322 | Parser.Lam t -> L (aux (level + 1) t)
\r
323 | Parser.App (t1, t2) ->
\r
324 if level = 0 then snd (mk_app dummy_p (aux level t1) (aux level t2))
\r
325 else A(aux level t1, aux level t2)
\r
326 | Parser.Var v -> V v
\r
327 in let (tms, free) = Parser.parse_many strs
\r
328 in (List.map (aux 0) tms, free)
\r
331 let magic6 div conv cmds =
\r
333 let all_tms, var_names = parse (div :: conv) in
\r
334 let div, conv = List.hd all_tms, List.tl all_tms in
\r
335 let freshno = 1 + List.length var_names in
\r
336 let p = {freshno; div; conv; matches=[]; sigma=[]} in
\r
338 let subst = Util.index_of "BOMB" var_names, L B in
\r
339 let p = subst_in_problem subst p in p
\r
340 with Not_found -> p in
\r
341 let p = sanity p in
\r
343 problem_fail (List.fold_left (|>) p cmds) "Problem not completed"
\r
348 let interactive div conv cmds =
\r
350 let all_tms, var_names = parse (div :: conv) in
\r
351 let div, conv = List.hd all_tms, List.tl all_tms in
\r
352 let freshno = 1 + List.length var_names in
\r
353 let p = {freshno; div; conv; matches=[]; sigma=[]} in
\r
355 let subst = Util.index_of "BOMB" var_names, L B in
\r
356 let p = subst_in_problem subst p in p
\r
357 with Not_found -> p in
\r
358 let p = sanity p in
\r
359 let p = List.fold_left (|>) p cmds in
\r
361 let nth spl n = int_of_string (List.nth spl n) in
\r
363 let s = read_line () in
\r
364 let spl = Str.split (Str.regexp " +") s in
\r
365 s, let uno = List.hd spl in
\r
366 try if uno = "explode" then explode
\r
367 else if uno = "ignore" then ignore (nth spl 1) (nth spl 2)
\r
368 else if uno = "step" then step (nth spl 1)
\r
369 else if uno = "perm" then perm (nth spl 1) (nth spl 2)
\r
370 else if uno = "apply" then apply (nth spl 1) (nth spl 2)
\r
371 else if uno = "id" then id (nth spl 1)
\r
372 else failwith "unknown"
\r
373 with Failure _ -> print_endline "Wrong input."; (fun x -> x) in
\r
374 let str, cmd = read_cmd () in
\r
375 let cmds = str::cmds in
\r
377 let p = cmd p in f p cmds
\r
379 | Done -> List.iter print_endline (List.rev cmds)
\r
386 [ ignore 1 1; explode ]
\r
392 [ perm 1 3; step 1 ; ignore 8 2; explode; ];;
\r
396 [ "x y BOMB d"; "x BOMB a2 c" ]
\r
397 [ perm 1 3 ; step 1 ; step 12; ignore 13 1; explode; ]
\r
402 [ "x x" ; "x x x" ] [
\r
411 [ "x (_._. BOMB)" ]
\r
418 [ apply 1 1; ignore 1 1; explode; ]
\r
422 "y (x a1 BOMB c) (x BOMB b1 d)"
\r
423 [ "y (x a2 BOMB c) (x BOMB b1 d)";
\r
424 "y (x a1 BOMB c) (x BOMB b2 d)";]
\r
425 [ perm 2 3; step 2; step 17; perm 16 2; step 16; ignore 19 1; ignore 20 1; ignore 22 1; ignore 23 1; step 1; step 26; explode; ]
\r
430 [ "z (y (x.x))"; "y (_. BOMB)" ]
\r
431 [ apply 2 1; step 3; explode' 8; ]
\r
436 [ "y (x.x)"; "x (_. BOMB)" ]
\r
437 [ apply 1 1; ignore 2 1; step 1; explode; ]
\r
442 [ "z (y (x.x))"; "y (_. BOMB)" ]
\r
443 [ step 1; explode; apply 2 1; id 2; ignore 3 1; ]
\r
448 [ "y (x b)"; "x BOMB" ] [
\r
455 "y (x a)" [ "y (x b)"; "x BOMB"; "y a" ]
\r
472 [ "y (x b)"; "x BOMB"; "y a" ] [];;
\r
474 print_endline "ALL DONE. "
\r