12 structure BNF_Sugar : BNF_SUGAR = |
12 structure BNF_Sugar : BNF_SUGAR = |
13 struct |
13 struct |
14 |
14 |
15 open BNF_Util |
15 open BNF_Util |
16 open BNF_FP_Util |
16 open BNF_FP_Util |
|
17 open BNF_Sugar_Tactics |
17 |
18 |
18 val distinctN = "distinct"; |
19 val distinctN = "distinct"; |
19 |
20 |
20 fun prepare_sugar prep_typ prep_term ((((raw_T, raw_ctors), raw_dtors), raw_storss), raw_recur) |
21 fun prepare_sugar prep_term (((raw_ctors, raw_dtors), raw_storss), raw_recur) |
21 lthy = |
22 lthy = |
22 let |
23 let |
23 (* TODO: sanity checks on arguments *) |
24 (* TODO: sanity checks on arguments *) |
24 |
25 |
25 val T as Type (T_name, _) = prep_typ lthy raw_T; |
|
26 val b = Binding.qualified_name T_name; |
|
27 |
|
28 val ctors = map (prep_term lthy) raw_ctors; |
26 val ctors = map (prep_term lthy) raw_ctors; |
29 val ctor_Tss = map (binder_types o fastype_of) ctors; |
27 val ctor_Tss = map (binder_types o fastype_of) ctors; |
30 |
28 |
31 val ((xss, yss), _) = lthy |> |
29 val T as Type (T_name, _) = body_type (fastype_of (hd ctors)); |
|
30 val b = Binding.qualified_name T_name; |
|
31 |
|
32 val n = length ctors; |
|
33 |
|
34 val ((((xss, yss), (v, v')), p), _) = lthy |> |
32 mk_Freess "x" ctor_Tss |
35 mk_Freess "x" ctor_Tss |
33 ||>> mk_Freess "y" ctor_Tss; |
36 ||>> mk_Freess "y" ctor_Tss |
|
37 ||>> yield_singleton (apfst (op ~~) oo mk_Frees' "v") T |
|
38 ||>> yield_singleton (mk_Frees "P") HOLogic.boolT; |
|
39 |
|
40 val xs_ctors = map2 (curry Term.list_comb) ctors xss; |
|
41 val ys_ctors = map2 (curry Term.list_comb) ctors yss; |
|
42 |
|
43 val goal_exhaust = |
|
44 let |
|
45 fun mk_imp_p Q = Logic.list_implies (Q, HOLogic.mk_Trueprop p); |
|
46 fun mk_prem xs_ctor xs = |
|
47 fold_rev Logic.all xs |
|
48 (mk_imp_p [HOLogic.mk_Trueprop (HOLogic.mk_eq (v, xs_ctor))]); |
|
49 in |
|
50 mk_imp_p (map2 mk_prem xs_ctors xss) |
|
51 end; |
34 |
52 |
35 val goal_injects = |
53 val goal_injects = |
36 let |
54 let |
37 fun mk_goal _ [] [] = NONE |
55 fun mk_goal _ _ [] [] = NONE |
38 | mk_goal ctor xs ys = |
56 | mk_goal xs_ctor ys_ctor xs ys = |
39 SOME (HOLogic.mk_Trueprop (HOLogic.mk_eq |
57 SOME (HOLogic.mk_Trueprop (HOLogic.mk_eq |
40 (HOLogic.mk_eq (Term.list_comb (ctor, xs), Term.list_comb (ctor, ys)), |
58 (HOLogic.mk_eq (xs_ctor, ys_ctor), |
41 Library.foldr1 HOLogic.mk_conj (map2 (curry HOLogic.mk_eq) xs ys)))); |
59 Library.foldr1 HOLogic.mk_conj (map2 (curry HOLogic.mk_eq) xs ys)))); |
42 in |
60 in |
43 map_filter I (map3 mk_goal ctors xss yss) |
61 map_filter I (map4 mk_goal xs_ctors ys_ctors xss yss) |
44 end; |
62 end; |
45 |
63 |
46 val goal_half_distincts = |
64 val goal_half_distincts = |
47 let |
65 let |
48 fun mk_goal t u = HOLogic.mk_Trueprop (HOLogic.mk_not (HOLogic.mk_eq (t, u))); |
66 fun mk_goal t u = HOLogic.mk_Trueprop (HOLogic.mk_not (HOLogic.mk_eq (t, u))); |
49 fun mk_goals [] = [] |
67 fun mk_goals [] = [] |
50 | mk_goals (t :: ts) = fold_rev (cons o mk_goal t) ts (mk_goals ts); |
68 | mk_goals (t :: ts) = fold_rev (cons o mk_goal t) ts (mk_goals ts); |
51 in |
69 in |
52 mk_goals (map2 (curry Term.list_comb) ctors xss) |
70 mk_goals xs_ctors |
53 end; |
71 end; |
54 |
72 |
55 val goals = [goal_injects, goal_half_distincts]; |
73 val goals = [[goal_exhaust], goal_injects, goal_half_distincts]; |
56 |
74 |
57 fun after_qed thmss lthy = |
75 fun after_qed thmss lthy = |
58 let |
76 let |
59 val [inject_thms, half_distinct_thms] = thmss; |
77 val [[exhaust_thm], inject_thms, half_distinct_thms] = thmss; |
60 |
78 |
61 val other_half_distinct_thms = map (fn thm => thm RS not_sym) half_distinct_thms; |
79 val other_half_distinct_thms = map (fn thm => thm RS not_sym) half_distinct_thms; |
|
80 |
|
81 val nchotomy_thm = |
|
82 let |
|
83 fun mk_disjunct xs_ctor xs = list_exists_free xs (HOLogic.mk_eq (v, xs_ctor)) |
|
84 val goal = |
|
85 HOLogic.mk_Trueprop |
|
86 (HOLogic.mk_all (fst v', snd v', |
|
87 Library.foldr1 HOLogic.mk_disj (map2 mk_disjunct xs_ctors xss))); |
|
88 in |
|
89 Skip_Proof.prove lthy [] [] goal (fn _ => mk_nchotomy_tac n exhaust_thm) |
|
90 end; |
62 |
91 |
63 fun note thmN thms = |
92 fun note thmN thms = |
64 snd o Local_Theory.note |
93 snd o Local_Theory.note |
65 ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), []), thms); |
94 ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), []), thms); |
66 in |
95 in |
67 lthy |
96 lthy |
|
97 |> note distinctN (half_distinct_thms @ other_half_distinct_thms) |
|
98 |> note exhaustN [exhaust_thm] |
68 |> note injectN inject_thms |
99 |> note injectN inject_thms |
69 |> note distinctN (half_distinct_thms @ other_half_distinct_thms) |
100 |> note nchotomyN [nchotomy_thm] |
70 end; |
101 end; |
71 in |
102 in |
72 (goals, after_qed, lthy) |
103 (goals, after_qed, lthy) |
73 end; |
104 end; |
74 |
105 |
75 val parse_binding_list = Parse.$$$ "[" |-- Parse.list Parse.binding --| Parse.$$$ "]"; |
106 val parse_binding_list = Parse.$$$ "[" |-- Parse.list Parse.binding --| Parse.$$$ "]"; |
76 |
107 |
77 val bnf_sugar_cmd = (fn (goalss, after_qed, lthy) => |
108 val bnf_sugar_cmd = (fn (goalss, after_qed, lthy) => |
78 Proof.theorem NONE after_qed (map (map (rpair [])) goalss) lthy) oo |
109 Proof.theorem NONE after_qed (map (map (rpair [])) goalss) lthy) oo |
79 prepare_sugar Syntax.read_typ Syntax.read_term; |
110 prepare_sugar Syntax.read_term; |
80 |
111 |
81 val _ = |
112 val _ = |
82 Outer_Syntax.local_theory_to_proof @{command_spec "bnf_sugar"} "adds sugar on top of a BNF" |
113 Outer_Syntax.local_theory_to_proof @{command_spec "bnf_sugar"} "adds sugar on top of a BNF" |
83 ((Parse.typ -- (Parse.$$$ "[" |-- Parse.list Parse.term --| Parse.$$$ "]") -- |
114 (((Parse.$$$ "[" |-- Parse.list Parse.term --| Parse.$$$ "]") -- |
84 parse_binding_list -- (Parse.$$$ "[" |-- Parse.list parse_binding_list --| Parse.$$$ "]") -- |
115 parse_binding_list -- (Parse.$$$ "[" |-- Parse.list parse_binding_list --| Parse.$$$ "]") -- |
85 Parse.term) >> bnf_sugar_cmd); |
116 Parse.term) >> bnf_sugar_cmd); |
86 |
117 |
87 end; |
118 end; |