243 |
266 |
244 fun atomize_term thy = MetaSimplifier.rewrite_term thy inductive_atomize []; |
267 fun atomize_term thy = MetaSimplifier.rewrite_term thy inductive_atomize []; |
245 |
268 |
246 in |
269 in |
247 |
270 |
248 fun check_rule thy cs params ((name, att), rule) = |
271 fun check_rule ctxt cs params ((name, att), rule) = |
249 let |
272 let |
250 val params' = Term.variant_frees rule (Logic.strip_params rule); |
273 val params' = Term.variant_frees rule (Logic.strip_params rule); |
251 val frees = rev (map Free params'); |
274 val frees = rev (map Free params'); |
252 val concl = subst_bounds (frees, Logic.strip_assums_concl rule); |
275 val concl = subst_bounds (frees, Logic.strip_assums_concl rule); |
253 val prems = map (curry subst_bounds frees) (Logic.strip_assums_hyp rule); |
276 val prems = map (curry subst_bounds frees) (Logic.strip_assums_hyp rule); |
254 val aprems = map (atomize_term thy) prems; |
277 val rule' = Logic.list_implies (prems, concl); |
|
278 val aprems = map (atomize_term (ProofContext.theory_of ctxt)) prems; |
255 val arule = list_all_free (params', Logic.list_implies (aprems, concl)); |
279 val arule = list_all_free (params', Logic.list_implies (aprems, concl)); |
256 |
280 |
257 fun check_ind err t = case dest_predicate cs params t of |
281 fun check_ind err t = case dest_predicate cs params t of |
258 NONE => err (bad_app ^ |
282 NONE => err (bad_app ^ |
259 commas (map (Sign.string_of_term thy) params)) |
283 commas (map (ProofContext.string_of_term ctxt) params)) |
260 | SOME (_, _, ys, _) => |
284 | SOME (_, _, ys, _) => |
261 if exists (fn c => exists (fn t => Logic.occs (c, t)) ys) cs |
285 if exists (fn c => exists (fn t => Logic.occs (c, t)) ys) cs |
262 then err bad_ind_occ else (); |
286 then err bad_ind_occ else (); |
263 |
287 |
264 fun check_prem' prem t = |
288 fun check_prem' prem t = |
265 if head_of t mem cs then |
289 if head_of t mem cs then |
266 check_ind (err_in_prem thy name rule prem) t |
290 check_ind (err_in_prem ctxt name rule prem) t |
267 else (case t of |
291 else (case t of |
268 Abs (_, _, t) => check_prem' prem t |
292 Abs (_, _, t) => check_prem' prem t |
269 | t $ u => (check_prem' prem t; check_prem' prem u) |
293 | t $ u => (check_prem' prem t; check_prem' prem u) |
270 | _ => ()); |
294 | _ => ()); |
271 |
295 |
272 fun check_prem (prem, aprem) = |
296 fun check_prem (prem, aprem) = |
273 if can HOLogic.dest_Trueprop aprem then check_prem' prem prem |
297 if can HOLogic.dest_Trueprop aprem then check_prem' prem prem |
274 else err_in_prem thy name rule prem "Non-atomic premise"; |
298 else err_in_prem ctxt name rule prem "Non-atomic premise"; |
275 in |
299 in |
276 (case concl of |
300 (case concl of |
277 Const ("Trueprop", _) $ t => |
301 Const ("Trueprop", _) $ t => |
278 if head_of t mem cs then |
302 if head_of t mem cs then |
279 (check_ind (err_in_rule thy name rule) t; |
303 (check_ind (err_in_rule ctxt name rule') t; |
280 List.app check_prem (prems ~~ aprems)) |
304 List.app check_prem (prems ~~ aprems)) |
281 else err_in_rule thy name rule bad_concl |
305 else err_in_rule ctxt name rule' bad_concl |
282 | _ => err_in_rule thy name rule bad_concl); |
306 | _ => err_in_rule ctxt name rule' bad_concl); |
283 ((name, att), arule) |
307 ((name, att), arule) |
284 end; |
308 end; |
285 |
309 |
286 val rulify = (* FIXME norm_hhf *) |
310 val rulify = (* FIXME norm_hhf *) |
287 hol_simplify inductive_conj |
311 hol_simplify inductive_conj |
640 in |
665 in |
641 (name_mx, (("", []), fold_rev lambda (params @ xs) |
666 (name_mx, (("", []), fold_rev lambda (params @ xs) |
642 (list_comb (rec_const, params @ make_bool_args' bs i @ |
667 (list_comb (rec_const, params @ make_bool_args' bs i @ |
643 make_args argTs (xs ~~ Ts))))) |
668 make_args argTs (xs ~~ Ts))))) |
644 end) (cnames_syn ~~ cs); |
669 end) (cnames_syn ~~ cs); |
645 val (consts_defs, ctxt'') = fold_map (LocalTheory.def Thm.internalK) specs ctxt'; |
670 val (consts_defs, ctxt'') = LocalTheory.defs Thm.internalK specs ctxt'; |
646 val preds = (case cs of [_] => [rec_const] | _ => map #1 consts_defs); |
671 val preds = (case cs of [_] => [rec_const] | _ => map #1 consts_defs); |
647 |
672 |
648 val mono = prove_mono predT fp_fun monos ctxt'' |
673 val mono = prove_mono predT fp_fun monos ctxt'' |
649 |
674 |
650 in (ctxt'', rec_name, mono, fp_def', map (#2 o #2) consts_defs, |
675 in (ctxt'', rec_name, mono, fp_def', map (#2 o #2) consts_defs, |
651 list_comb (rec_const, params), preds, argTs, bs, xs) |
676 list_comb (rec_const, params), preds, argTs, bs, xs) |
652 end; |
677 end; |
653 |
678 |
654 fun add_ind_def verbose alt_name coind no_elim no_ind cs |
679 fun declare_rules rec_name coind no_ind cnames intrs intr_names intr_atts |
655 intros monos params cnames_syn ctxt = |
680 elims raw_induct ctxt = |
656 let |
681 let |
657 val _ = |
682 val ind_case_names = RuleCases.case_names intr_names; |
658 if verbose then message ("Proofs for " ^ coind_prefix coind ^ "inductive predicate(s) " ^ |
|
659 commas_quote (map fst cnames_syn)) else (); |
|
660 |
|
661 val cnames = map (Sign.full_name (ProofContext.theory_of ctxt) o #1) cnames_syn; (* FIXME *) |
|
662 val ((intr_names, intr_atts), intr_ts) = apfst split_list (split_list intros); |
|
663 |
|
664 val (ctxt1, rec_name, mono, fp_def, rec_preds_defs, rec_const, preds, |
|
665 argTs, bs, xs) = mk_ind_def alt_name coind cs intr_ts |
|
666 monos params cnames_syn ctxt; |
|
667 |
|
668 val (intrs, unfold) = prove_intrs coind mono fp_def (length bs + length xs) |
|
669 params intr_ts rec_preds_defs ctxt1; |
|
670 val elims = if no_elim then [] else |
|
671 cnames ~~ prove_elims cs params intr_ts intr_names unfold rec_preds_defs ctxt1; |
|
672 val raw_induct = zero_var_indexes |
|
673 (if no_ind then Drule.asm_rl else |
|
674 if coind then ObjectLogic.rulify (rule_by_tactic |
|
675 (rewrite_tac [le_fun_def, le_bool_def] THEN |
|
676 fold_tac rec_preds_defs) (mono RS (fp_def RS def_coinduct))) |
|
677 else |
|
678 prove_indrule cs argTs bs xs rec_const params intr_ts mono fp_def |
|
679 rec_preds_defs ctxt1); |
|
680 val induct_cases = map (#1 o #1) intros; |
|
681 val ind_case_names = RuleCases.case_names induct_cases; |
|
682 val induct = |
683 val induct = |
683 if coind then |
684 if coind then |
684 (raw_induct, [RuleCases.case_names [rec_name], |
685 (raw_induct, [RuleCases.case_names [rec_name], |
685 RuleCases.case_conclusion (rec_name, induct_cases), |
686 RuleCases.case_conclusion (rec_name, intr_names), |
686 RuleCases.consumes 1]) |
687 RuleCases.consumes 1, InductAttrib.coinduct_set (hd cnames)]) |
687 else if no_ind orelse length cs > 1 then |
688 else if no_ind orelse length cnames > 1 then |
688 (raw_induct, [ind_case_names, RuleCases.consumes 0]) |
689 (raw_induct, [ind_case_names, RuleCases.consumes 0]) |
689 else (raw_induct RSN (2, rev_mp), [ind_case_names, RuleCases.consumes 1]); |
690 else (raw_induct RSN (2, rev_mp), [ind_case_names, RuleCases.consumes 1]); |
690 |
691 |
691 val (intrs', ctxt2) = |
692 val (intrs', ctxt1) = |
692 ctxt1 |> |
693 ctxt |> |
693 note_theorems |
694 note_theorems |
694 (map (NameSpace.qualified rec_name) intr_names ~~ |
695 (map (NameSpace.qualified rec_name) intr_names ~~ |
695 intr_atts ~~ map (fn th => [([th], |
696 intr_atts ~~ map (fn th => [([th], |
696 [Attrib.internal (K (ContextRules.intro_query NONE))])]) intrs) |>> |
697 [Attrib.internal (K (ContextRules.intro_query NONE))])]) intrs) |>> |
697 map (hd o snd); (* FIXME? *) |
698 map (hd o snd); (* FIXME? *) |
698 val (((_, elims'), (_, [induct'])), ctxt3) = |
699 val (((_, elims'), (_, [induct'])), ctxt2) = |
699 ctxt2 |> |
700 ctxt1 |> |
700 note_theorem ((NameSpace.qualified rec_name "intros", []), intrs') ||>> |
701 note_theorem ((NameSpace.qualified rec_name "intros", []), intrs') ||>> |
701 fold_map (fn (name, (elim, cases)) => |
702 fold_map (fn (name, (elim, cases)) => |
702 note_theorem ((NameSpace.qualified (Sign.base_name name) "cases", |
703 note_theorem ((NameSpace.qualified (Sign.base_name name) "cases", |
703 [Attrib.internal (K (RuleCases.case_names cases)), |
704 [Attrib.internal (K (RuleCases.case_names cases)), |
704 Attrib.internal (K (RuleCases.consumes 1)), |
705 Attrib.internal (K (RuleCases.consumes 1)), |
705 Attrib.internal (K (InductAttrib.cases_set name)), |
706 Attrib.internal (K (InductAttrib.cases_set name)), |
706 Attrib.internal (K (ContextRules.elim_query NONE))]), [elim]) #> |
707 Attrib.internal (K (ContextRules.elim_query NONE))]), [elim]) #> |
707 apfst (hd o snd)) elims ||>> |
708 apfst (hd o snd)) (if null elims then [] else cnames ~~ elims) ||>> |
708 note_theorem ((NameSpace.qualified rec_name (coind_prefix coind ^ "induct"), |
709 note_theorem ((NameSpace.qualified rec_name (coind_prefix coind ^ "induct"), |
709 map (Attrib.internal o K) (#2 induct)), [rulify (#1 induct)]); |
710 map (Attrib.internal o K) (#2 induct)), [rulify (#1 induct)]); |
710 |
711 |
711 val induct_att = if coind then InductAttrib.coinduct_set else InductAttrib.induct_set; |
712 val ctxt3 = if no_ind orelse coind then ctxt2 else |
712 val ctxt4 = if no_ind then ctxt3 else |
713 let val inducts = cnames ~~ ProjectRule.projects ctxt2 (1 upto length cnames) induct' |
713 let val inducts = cnames ~~ ProjectRule.projects ctxt (1 upto length cnames) induct' |
|
714 in |
714 in |
715 ctxt3 |> |
715 ctxt2 |> |
716 note_theorems [((NameSpace.qualified rec_name (coind_prefix coind ^ "inducts"), []), |
716 note_theorems [((NameSpace.qualified rec_name "inducts", []), |
717 inducts |> map (fn (name, th) => ([th], |
717 inducts |> map (fn (name, th) => ([th], |
718 [Attrib.internal (K ind_case_names), |
718 [Attrib.internal (K ind_case_names), |
719 Attrib.internal (K (RuleCases.consumes 1)), |
719 Attrib.internal (K (RuleCases.consumes 1)), |
720 Attrib.internal (K (induct_att name))])))] |> snd |
720 Attrib.internal (K (InductAttrib.induct_set name))])))] |> snd |
721 end; |
721 end |
|
722 in (intrs', elims', induct', ctxt3) end; |
|
723 |
|
724 type add_ind_def = bool -> bstring -> bool -> bool -> bool -> |
|
725 term list -> ((string * Attrib.src list) * term) list -> thm list -> |
|
726 term list -> (string * mixfix) list -> |
|
727 local_theory -> inductive_result * local_theory |
|
728 |
|
729 fun add_ind_def verbose alt_name coind no_elim no_ind cs |
|
730 intros monos params cnames_syn ctxt = |
|
731 let |
|
732 val _ = |
|
733 if verbose then message ("Proofs for " ^ coind_prefix coind ^ "inductive predicate(s) " ^ |
|
734 commas_quote (map fst cnames_syn)) else (); |
|
735 |
|
736 val cnames = map (Sign.full_name (ProofContext.theory_of ctxt) o #1) cnames_syn; (* FIXME *) |
|
737 val ((intr_names, intr_atts), intr_ts) = |
|
738 apfst split_list (split_list (map (check_rule ctxt cs params) intros)); |
|
739 |
|
740 val (ctxt1, rec_name, mono, fp_def, rec_preds_defs, rec_const, preds, |
|
741 argTs, bs, xs) = mk_ind_def alt_name coind cs intr_ts |
|
742 monos params cnames_syn ctxt; |
|
743 |
|
744 val (intrs, unfold) = prove_intrs coind mono fp_def (length bs + length xs) |
|
745 params intr_ts rec_preds_defs ctxt1; |
|
746 val elims = if no_elim then [] else |
|
747 prove_elims cs params intr_ts intr_names unfold rec_preds_defs ctxt1; |
|
748 val raw_induct = zero_var_indexes |
|
749 (if no_ind then Drule.asm_rl else |
|
750 if coind then |
|
751 singleton (ProofContext.export |
|
752 (snd (Variable.add_fixes (map (fst o dest_Free) params) ctxt1)) ctxt1) |
|
753 (rotate_prems ~1 (ObjectLogic.rulify (rule_by_tactic |
|
754 (rewrite_tac [le_fun_def, le_bool_def, sup_fun_eq, sup_bool_eq] THEN |
|
755 fold_tac rec_preds_defs) (mono RS (fp_def RS def_coinduct))))) |
|
756 else |
|
757 prove_indrule cs argTs bs xs rec_const params intr_ts mono fp_def |
|
758 rec_preds_defs ctxt1); |
|
759 |
|
760 val (intrs', elims', induct, ctxt2) = declare_rules rec_name coind no_ind |
|
761 cnames intrs intr_names intr_atts elims raw_induct ctxt1; |
722 |
762 |
723 val names = map #1 cnames_syn; |
763 val names = map #1 cnames_syn; |
724 val result = |
764 val result = |
725 {preds = preds, |
765 {preds = preds, |
726 defs = fp_def :: rec_preds_defs, |
|
727 mono = mono, |
|
728 unfold = unfold, |
|
729 intrs = intrs', |
766 intrs = intrs', |
730 elims = elims', |
767 elims = elims', |
731 raw_induct = rulify raw_induct, |
768 raw_induct = rulify raw_induct, |
732 induct = induct'}; |
769 induct = induct}; |
733 |
770 |
734 val ctxt5 = ctxt4 |
771 val ctxt3 = ctxt2 |
735 |> Context.proof_map (put_inductives names ({names = names, coind = coind}, result)) |
772 |> Context.proof_map (put_inductives names ({names = names, coind = coind}, result)) |
736 |> LocalTheory.declaration (fn phi => |
773 |> LocalTheory.declaration (fn phi => |
737 let |
774 let |
738 val names' = map (LocalTheory.target_name ctxt4 o Morphism.name phi) names; |
775 val names' = map (LocalTheory.target_name ctxt2 o Morphism.name phi) names; |
739 val result' = morph_result phi result; |
776 val result' = morph_result phi result; |
740 in put_inductives names' ({names = names', coind = coind}, result') end); |
777 in put_inductives names' ({names = names', coind = coind}, result') end); |
741 in (result, ctxt5) end; |
778 in (result, ctxt3) end; |
742 |
779 |
743 |
780 |
744 (* external interfaces *) |
781 (* external interfaces *) |
745 |
782 |
746 fun add_inductive_i verbose alt_name coind no_elim no_ind cnames_syn pnames pre_intros monos ctxt = |
783 fun gen_add_inductive_i mk_def verbose alt_name coind no_elim no_ind |
|
784 cnames_syn pnames pre_intros monos ctxt = |
747 let |
785 let |
748 val thy = ProofContext.theory_of ctxt; |
786 val thy = ProofContext.theory_of ctxt; |
749 val _ = Theory.requires thy "Inductive" (coind_prefix coind ^ "inductive definitions"); |
787 val _ = Theory.requires thy "Inductive" (coind_prefix coind ^ "inductive definitions"); |
750 |
788 |
751 val frees = fold (Term.add_frees o snd) pre_intros []; |
789 val frees = fold (Term.add_frees o snd) pre_intros []; |
908 else if b = "" then ((a, atts), B) |
948 else if b = "" then ((a, atts), B) |
909 else error ("Illegal nested case names " ^ quote (NameSpace.append a b)) |
949 else error ("Illegal nested case names " ^ quote (NameSpace.append a b)) |
910 | ((b, _), _) => error ("Illegal simultaneous specification " ^ quote b)) |
950 | ((b, _), _) => error ("Illegal simultaneous specification " ^ quote b)) |
911 | (a, _) => error ("Illegal local specification parameters for " ^ quote a)); |
951 | (a, _) => error ("Illegal local specification parameters for " ^ quote a)); |
912 |
952 |
913 fun ind_decl coind = |
953 fun gen_ind_decl mk_def coind = |
914 P.opt_target -- |
954 P.opt_target -- |
915 P.fixes -- P.for_fixes -- |
955 P.fixes -- P.for_fixes -- |
916 Scan.optional (P.$$$ "where" |-- P.!!! SpecParse.specification) [] -- |
956 Scan.optional (P.$$$ "where" |-- P.!!! SpecParse.specification) [] -- |
917 Scan.optional (P.$$$ "monos" |-- P.!!! SpecParse.xthms1) [] |
957 Scan.optional (P.$$$ "monos" |-- P.!!! SpecParse.xthms1) [] |
918 >> (fn ((((loc, preds), params), specs), monos) => |
958 >> (fn ((((loc, preds), params), specs), monos) => |
919 Toplevel.local_theory loc |
959 Toplevel.local_theory loc |
920 (fn lthy => lthy |
960 (fn lthy => lthy |> gen_add_inductive mk_def true coind preds params |
921 |> add_inductive true coind preds params (flatten_specification specs) monos |> snd)); |
961 (flatten_specification specs) monos |> snd)); |
|
962 |
|
963 val ind_decl = gen_ind_decl add_ind_def; |
922 |
964 |
923 val inductiveP = |
965 val inductiveP = |
924 OuterSyntax.command "inductive2" "define inductive predicates" K.thy_decl (ind_decl false); |
966 OuterSyntax.command "inductive" "define inductive predicates" K.thy_decl (ind_decl false); |
925 |
967 |
926 val coinductiveP = |
968 val coinductiveP = |
927 OuterSyntax.command "coinductive2" "define coinductive predicates" K.thy_decl (ind_decl true); |
969 OuterSyntax.command "coinductive" "define coinductive predicates" K.thy_decl (ind_decl true); |
928 |
970 |
929 |
971 |
930 val inductive_casesP = |
972 val inductive_casesP = |
931 OuterSyntax.command "inductive_cases2" |
973 OuterSyntax.command "inductive_cases" |
932 "create simplified instances of elimination rules (improper)" K.thy_script |
974 "create simplified instances of elimination rules (improper)" K.thy_script |
933 (P.opt_target -- P.and_list1 SpecParse.spec |
975 (P.opt_target -- P.and_list1 SpecParse.spec |
934 >> (fn (loc, specs) => Toplevel.local_theory loc (snd o inductive_cases specs))); |
976 >> (fn (loc, specs) => Toplevel.local_theory loc (snd o inductive_cases specs))); |
935 |
977 |
936 val _ = OuterSyntax.add_keywords ["monos"]; |
978 val _ = OuterSyntax.add_keywords ["monos"]; |