src/HOL/Codatatype/Tools/bnf_fp_sugar.ML
changeset 49504 df9b897fb254
parent 49502 92a7c1842c78
child 49505 a944eefb67e6
equal deleted inserted replaced
49503:dbbde075a42e 49504:df9b897fb254
   167     val ctr_sum_prod_TsBs = map (mk_sumTN_balanced o map HOLogic.mk_tupleT) ctr_TsssBs;
   167     val ctr_sum_prod_TsBs = map (mk_sumTN_balanced o map HOLogic.mk_tupleT) ctr_TsssBs;
   168 
   168 
   169     val fp_eqs =
   169     val fp_eqs =
   170       map dest_TFree Bs ~~ map (Term.typ_subst_atomic (As ~~ unsorted_As)) ctr_sum_prod_TsBs;
   170       map dest_TFree Bs ~~ map (Term.typ_subst_atomic (As ~~ unsorted_As)) ctr_sum_prod_TsBs;
   171 
   171 
   172     val (pre_bnfs, ((dtors0, ctors0, fp_iters0, fp_recs0, fp_induct, dtor_ctors, ctor_dtors,
   172     val (pre_bnfs, ((dtors0, ctors0, fp_folds0, fp_recs0, fp_induct, dtor_ctors, ctor_dtors,
   173            ctor_injects, fp_iter_thms, fp_rec_thms), lthy)) =
   173            ctor_injects, fp_fold_thms, fp_rec_thms), lthy)) =
   174       fp_bnf construct fp_bs mixfixes (map dest_TFree unsorted_As) fp_eqs no_defs_lthy0;
   174       fp_bnf construct fp_bs mixfixes (map dest_TFree unsorted_As) fp_eqs no_defs_lthy0;
   175 
   175 
   176     fun add_nesty_bnf_names Us =
   176     fun add_nesty_bnf_names Us =
   177       let
   177       let
   178         fun add (Type (s, Ts)) ss =
   178         fun add (Type (s, Ts)) ss =
   209     val ns = map length ctr_Tsss;
   209     val ns = map length ctr_Tsss;
   210     val kss = map (fn n => 1 upto n) ns;
   210     val kss = map (fn n => 1 upto n) ns;
   211     val mss = map (map length) ctr_Tsss;
   211     val mss = map (map length) ctr_Tsss;
   212     val Css = map2 replicate ns Cs;
   212     val Css = map2 replicate ns Cs;
   213 
   213 
   214     fun mk_iter_like Ts Us t =
   214     fun mk_rec_like Ts Us t =
   215       let
   215       let
   216         val (bindings, body) = strip_type (fastype_of t);
   216         val (bindings, body) = strip_type (fastype_of t);
   217         val (f_Us, prebody) = split_last bindings;
   217         val (f_Us, prebody) = split_last bindings;
   218         val Type (_, Ts0) = if lfp then prebody else body;
   218         val Type (_, Ts0) = if lfp then prebody else body;
   219         val Us0 = distinct (op =) (map (if lfp then body_type else domain_type) f_Us);
   219         val Us0 = distinct (op =) (map (if lfp then body_type else domain_type) f_Us);
   220       in
   220       in
   221         Term.subst_atomic_types (Ts0 @ Us0 ~~ Ts @ Us) t
   221         Term.subst_atomic_types (Ts0 @ Us0 ~~ Ts @ Us) t
   222       end;
   222       end;
   223 
   223 
   224     val fp_iters as fp_iter1 :: _ = map (mk_iter_like As Cs) fp_iters0;
   224     val fp_folds as fp_fold1 :: _ = map (mk_rec_like As Cs) fp_folds0;
   225     val fp_recs as fp_rec1 :: _ = map (mk_iter_like As Cs) fp_recs0;
   225     val fp_recs as fp_rec1 :: _ = map (mk_rec_like As Cs) fp_recs0;
   226 
   226 
   227     val fp_iter_fun_Ts = fst (split_last (binder_types (fastype_of fp_iter1)));
   227     val fp_fold_fun_Ts = fst (split_last (binder_types (fastype_of fp_fold1)));
   228     val fp_rec_fun_Ts = fst (split_last (binder_types (fastype_of fp_rec1)));
   228     val fp_rec_fun_Ts = fst (split_last (binder_types (fastype_of fp_rec1)));
   229 
   229 
   230     val (((iter_only as (gss, _, _), rec_only as (hss, _, _)),
   230     val (((fold_only as (gss, _, _), rec_only as (hss, _, _)),
   231           (zs, cs, cpss, coiter_only as ((pgss, crgsss), _), corec_only as ((phss, cshsss), _))),
   231           (zs, cs, cpss, unfold_only as ((pgss, crgsss), _), corec_only as ((phss, cshsss), _))),
   232          names_lthy) =
   232          names_lthy) =
   233       if lfp then
   233       if lfp then
   234         let
   234         let
   235           val y_Tsss =
   235           val y_Tsss =
   236             map3 (fn n => fn ms => map2 dest_tupleT ms o dest_sumTN_balanced n o domain_type)
   236             map3 (fn n => fn ms => map2 dest_tupleT ms o dest_sumTN_balanced n o domain_type)
   237               ns mss fp_iter_fun_Ts;
   237               ns mss fp_fold_fun_Ts;
   238           val g_Tss = map2 (map2 (curry (op --->))) y_Tsss Css;
   238           val g_Tss = map2 (map2 (curry (op --->))) y_Tsss Css;
   239 
   239 
   240           val ((gss, ysss), lthy) =
   240           val ((gss, ysss), lthy) =
   241             lthy
   241             lthy
   242             |> mk_Freess "f" g_Tss
   242             |> mk_Freess "f" g_Tss
   285               val q_Tssss =
   285               val q_Tssss =
   286                 map (map (map (fn [_] => [] | [_, C] => [mk_pred1T (domain_type C)]))) f_Tssss;
   286                 map (map (map (fn [_] => [] | [_, C] => [mk_pred1T (domain_type C)]))) f_Tssss;
   287               val pf_Tss = map3 zip_preds_predsss_gettersss p_Tss q_Tssss f_Tssss;
   287               val pf_Tss = map3 zip_preds_predsss_gettersss p_Tss q_Tssss f_Tssss;
   288             in (q_Tssss, f_sum_prod_Ts, f_Tssss, pf_Tss) end;
   288             in (q_Tssss, f_sum_prod_Ts, f_Tssss, pf_Tss) end;
   289 
   289 
   290           val (r_Tssss, g_sum_prod_Ts, g_Tssss, pg_Tss) = mk_types single fp_iter_fun_Ts;
   290           val (r_Tssss, g_sum_prod_Ts, g_Tssss, pg_Tss) = mk_types single fp_fold_fun_Ts;
   291 
   291 
   292           val ((((Free (z, _), cs), pss), gssss), lthy) =
   292           val ((((Free (z, _), cs), pss), gssss), lthy) =
   293             lthy
   293             lthy
   294             |> yield_singleton (mk_Frees "z") dummyT
   294             |> yield_singleton (mk_Frees "z") dummyT
   295             ||>> mk_Frees "a" Cs
   295             ||>> mk_Frees "a" Cs
   327           (((([], [], []), ([], [], [])),
   327           (((([], [], []), ([], [], [])),
   328             ([z], cs, cpss, (mk_terms rssss gssss, (g_sum_prod_Ts, pg_Tss)),
   328             ([z], cs, cpss, (mk_terms rssss gssss, (g_sum_prod_Ts, pg_Tss)),
   329              (mk_terms sssss hssss, (h_sum_prod_Ts, ph_Tss)))), lthy)
   329              (mk_terms sssss hssss, (h_sum_prod_Ts, ph_Tss)))), lthy)
   330         end;
   330         end;
   331 
   331 
   332     fun define_ctrs_case_for_type ((((((((((((((((((fp_b, fpT), C), ctor), dtor), fp_iter), fp_rec),
   332     fun define_ctrs_case_for_type ((((((((((((((((((fp_b, fpT), C), ctor), dtor), fp_fold), fp_rec),
   333           ctor_dtor), dtor_ctor), ctor_inject), n), ks), ms), ctr_bindings), ctr_mixfixes), ctr_Tss),
   333           ctor_dtor), dtor_ctor), ctor_inject), n), ks), ms), ctr_bindings), ctr_mixfixes), ctr_Tss),
   334         disc_bindings), sel_bindingss), raw_sel_defaultss) no_defs_lthy =
   334         disc_bindings), sel_bindingss), raw_sel_defaultss) no_defs_lthy =
   335       let
   335       let
   336         val fp_b_name = Binding.name_of fp_b;
   336         val fp_b_name = Binding.name_of fp_b;
   337 
   337 
   389                 |> Thm.close_derivation
   389                 |> Thm.close_derivation
   390                 |> Morphism.thm phi
   390                 |> Morphism.thm phi
   391               end;
   391               end;
   392 
   392 
   393             val sumEN_thm' =
   393             val sumEN_thm' =
   394               unfold_defs lthy @{thms all_unit_eq}
   394               unfold_thms lthy @{thms all_unit_eq}
   395                 (Drule.instantiate' (map (SOME o certifyT lthy) ctr_prod_Ts) []
   395                 (Drule.instantiate' (map (SOME o certifyT lthy) ctr_prod_Ts) []
   396                    (mk_sumEN_balanced n))
   396                    (mk_sumEN_balanced n))
   397               |> Morphism.thm phi;
   397               |> Morphism.thm phi;
   398           in
   398           in
   399             mk_exhaust_tac ctxt n ctr_defs ctor_iff_dtor_thm sumEN_thm'
   399             mk_exhaust_tac ctxt n ctr_defs ctor_iff_dtor_thm sumEN_thm'
   411           map3 (fn k => fn m => fn ctr_def => fn {context = ctxt, ...} =>
   411           map3 (fn k => fn m => fn ctr_def => fn {context = ctxt, ...} =>
   412             mk_case_tac ctxt n k m case_def ctr_def dtor_ctor) ks ms ctr_defs;
   412             mk_case_tac ctxt n k m case_def ctr_def dtor_ctor) ks ms ctr_defs;
   413 
   413 
   414         val tacss = [exhaust_tac] :: inject_tacss @ half_distinct_tacss @ [case_tacs];
   414         val tacss = [exhaust_tac] :: inject_tacss @ half_distinct_tacss @ [case_tacs];
   415 
   415 
   416         fun define_iter_rec (wrap_res, no_defs_lthy) =
   416         fun define_fold_rec (wrap_res, no_defs_lthy) =
   417           let
   417           let
   418             val fpT_to_C = fpT --> C;
   418             val fpT_to_C = fpT --> C;
   419 
   419 
   420             fun generate_iter_like (suf, fp_iter_like, (fss, f_Tss, xssss)) =
   420             fun generate_rec_like (suf, fp_rec_like, (fss, f_Tss, xssss)) =
   421               let
   421               let
   422                 val res_T = fold_rev (curry (op --->)) f_Tss fpT_to_C;
   422                 val res_T = fold_rev (curry (op --->)) f_Tss fpT_to_C;
   423                 val binding = Binding.suffix_name ("_" ^ suf) fp_b;
   423                 val binding = Binding.suffix_name ("_" ^ suf) fp_b;
   424                 val spec =
   424                 val spec =
   425                   mk_Trueprop_eq (lists_bmoc fss (Free (Binding.name_of binding, res_T)),
   425                   mk_Trueprop_eq (lists_bmoc fss (Free (Binding.name_of binding, res_T)),
   426                     Term.list_comb (fp_iter_like,
   426                     Term.list_comb (fp_rec_like,
   427                       map2 (mk_sum_caseN_balanced oo map2 mk_uncurried2_fun) fss xssss));
   427                       map2 (mk_sum_caseN_balanced oo map2 mk_uncurried2_fun) fss xssss));
   428               in (binding, spec) end;
   428               in (binding, spec) end;
   429 
   429 
   430             val iter_like_infos =
   430             val rec_like_infos =
   431               [(iterN, fp_iter, iter_only),
   431               [(foldN, fp_fold, fold_only),
   432                (recN, fp_rec, rec_only)];
   432                (recN, fp_rec, rec_only)];
   433 
   433 
   434             val (bindings, specs) = map generate_iter_like iter_like_infos |> split_list;
   434             val (bindings, specs) = map generate_rec_like rec_like_infos |> split_list;
   435 
   435 
   436             val ((csts, defs), (lthy', lthy)) = no_defs_lthy
   436             val ((csts, defs), (lthy', lthy)) = no_defs_lthy
   437               |> apfst split_list o fold_map2 (fn b => fn spec =>
   437               |> apfst split_list o fold_map2 (fn b => fn spec =>
   438                 Specification.definition (SOME (b, NONE, NoSyn), ((Thm.def_binding b, []), spec))
   438                 Specification.definition (SOME (b, NONE, NoSyn), ((Thm.def_binding b, []), spec))
   439                 #>> apsnd snd) bindings specs
   439                 #>> apsnd snd) bindings specs
   440               ||> `Local_Theory.restore;
   440               ||> `Local_Theory.restore;
   441 
   441 
   442             val phi = Proof_Context.export_morphism lthy lthy';
   442             val phi = Proof_Context.export_morphism lthy lthy';
   443 
   443 
   444             val [iter_def, rec_def] = map (Morphism.thm phi) defs;
   444             val [fold_def, rec_def] = map (Morphism.thm phi) defs;
   445 
   445 
   446             val [iterx, recx] = map (mk_iter_like As Cs o Morphism.term phi) csts;
   446             val [foldx, recx] = map (mk_rec_like As Cs o Morphism.term phi) csts;
   447           in
   447           in
   448             ((wrap_res, ctrs, iterx, recx, xss, ctr_defs, iter_def, rec_def), lthy)
   448             ((wrap_res, ctrs, foldx, recx, xss, ctr_defs, fold_def, rec_def), lthy)
   449           end;
   449           end;
   450 
   450 
   451         fun define_coiter_corec (wrap_res, no_defs_lthy) =
   451         fun define_unfold_corec (wrap_res, no_defs_lthy) =
   452           let
   452           let
   453             val B_to_fpT = C --> fpT;
   453             val B_to_fpT = C --> fpT;
   454 
   454 
   455             fun mk_preds_getterss_join c n cps sum_prod_T cqfss =
   455             fun mk_preds_getterss_join c n cps sum_prod_T cqfss =
   456               Term.lambda c (mk_IfN sum_prod_T cps
   456               Term.lambda c (mk_IfN sum_prod_T cps
   457                 (map2 (mk_InN_balanced sum_prod_T n) (map HOLogic.mk_tuple cqfss) (1 upto n)));
   457                 (map2 (mk_InN_balanced sum_prod_T n) (map HOLogic.mk_tuple cqfss) (1 upto n)));
   458 
   458 
   459             fun generate_coiter_like (suf, fp_iter_like, ((pfss, cqfsss), (f_sum_prod_Ts,
   459             fun generate_corec_like (suf, fp_rec_like, ((pfss, cqfsss), (f_sum_prod_Ts,
   460                 pf_Tss))) =
   460                 pf_Tss))) =
   461               let
   461               let
   462                 val res_T = fold_rev (curry (op --->)) pf_Tss B_to_fpT;
   462                 val res_T = fold_rev (curry (op --->)) pf_Tss B_to_fpT;
   463                 val binding = Binding.suffix_name ("_" ^ suf) fp_b;
   463                 val binding = Binding.suffix_name ("_" ^ suf) fp_b;
   464                 val spec =
   464                 val spec =
   465                   mk_Trueprop_eq (lists_bmoc pfss (Free (Binding.name_of binding, res_T)),
   465                   mk_Trueprop_eq (lists_bmoc pfss (Free (Binding.name_of binding, res_T)),
   466                     Term.list_comb (fp_iter_like,
   466                     Term.list_comb (fp_rec_like,
   467                       map5 mk_preds_getterss_join cs ns cpss f_sum_prod_Ts cqfsss));
   467                       map5 mk_preds_getterss_join cs ns cpss f_sum_prod_Ts cqfsss));
   468               in (binding, spec) end;
   468               in (binding, spec) end;
   469 
   469 
   470             val coiter_like_infos =
   470             val corec_like_infos =
   471               [(coiterN, fp_iter, coiter_only),
   471               [(unfoldN, fp_fold, unfold_only),
   472                (corecN, fp_rec, corec_only)];
   472                (corecN, fp_rec, corec_only)];
   473 
   473 
   474             val (bindings, specs) = map generate_coiter_like coiter_like_infos |> split_list;
   474             val (bindings, specs) = map generate_corec_like corec_like_infos |> split_list;
   475 
   475 
   476             val ((csts, defs), (lthy', lthy)) = no_defs_lthy
   476             val ((csts, defs), (lthy', lthy)) = no_defs_lthy
   477               |> apfst split_list o fold_map2 (fn b => fn spec =>
   477               |> apfst split_list o fold_map2 (fn b => fn spec =>
   478                 Specification.definition (SOME (b, NONE, NoSyn), ((Thm.def_binding b, []), spec))
   478                 Specification.definition (SOME (b, NONE, NoSyn), ((Thm.def_binding b, []), spec))
   479                 #>> apsnd snd) bindings specs
   479                 #>> apsnd snd) bindings specs
   480               ||> `Local_Theory.restore;
   480               ||> `Local_Theory.restore;
   481 
   481 
   482             val phi = Proof_Context.export_morphism lthy lthy';
   482             val phi = Proof_Context.export_morphism lthy lthy';
   483 
   483 
   484             val [coiter_def, corec_def] = map (Morphism.thm phi) defs;
   484             val [unfold_def, corec_def] = map (Morphism.thm phi) defs;
   485 
   485 
   486             val [coiter, corec] = map (mk_iter_like As Cs o Morphism.term phi) csts;
   486             val [unfold, corec] = map (mk_rec_like As Cs o Morphism.term phi) csts;
   487           in
   487           in
   488             ((wrap_res, ctrs, coiter, corec, xss, ctr_defs, coiter_def, corec_def), lthy)
   488             ((wrap_res, ctrs, unfold, corec, xss, ctr_defs, unfold_def, corec_def), lthy)
   489           end;
   489           end;
   490 
   490 
   491         fun wrap lthy =
   491         fun wrap lthy =
   492           let val sel_defaultss = map (map (apsnd (prepare_term lthy))) raw_sel_defaultss in
   492           let val sel_defaultss = map (map (apsnd (prepare_term lthy))) raw_sel_defaultss in
   493             wrap_datatype tacss (((no_dests, ctrs0), casex0), (disc_bindings, (sel_bindingss,
   493             wrap_datatype tacss (((no_dests, ctrs0), casex0), (disc_bindings, (sel_bindingss,
   494               sel_defaultss))) lthy
   494               sel_defaultss))) lthy
   495           end;
   495           end;
   496 
   496 
   497         val define_iter_likes = if lfp then define_iter_rec else define_coiter_corec;
   497         val define_rec_likes = if lfp then define_fold_rec else define_unfold_corec;
   498       in
   498       in
   499         ((wrap, define_iter_likes), lthy')
   499         ((wrap, define_rec_likes), lthy')
   500       end;
   500       end;
   501 
   501 
   502     val pre_map_defs = map map_def_of_bnf pre_bnfs;
   502     val pre_map_defs = map map_def_of_bnf pre_bnfs;
   503     val pre_set_defss = map set_defs_of_bnf pre_bnfs;
   503     val pre_set_defss = map set_defs_of_bnf pre_bnfs;
   504     val nested_set_natural's = maps set_natural'_of_bnf nested_bnfs;
   504     val nested_set_natural's = maps set_natural'_of_bnf nested_bnfs;
   519         val TUs = map dest_funT (fst (strip_typeN live (fastype_of mapx)));
   519         val TUs = map dest_funT (fst (strip_typeN live (fastype_of mapx)));
   520         val args = map build_arg TUs;
   520         val args = map build_arg TUs;
   521       in Term.list_comb (mapx, args) end;
   521       in Term.list_comb (mapx, args) end;
   522 
   522 
   523     val mk_simp_thmss =
   523     val mk_simp_thmss =
   524       map3 (fn (_, _, injects, distincts, cases, _, _, _) => fn rec_likes => fn iter_likes =>
   524       map3 (fn (_, _, injects, distincts, cases, _, _, _) => fn rec_likes => fn rec_likes =>
   525         injects @ distincts @ cases @ rec_likes @ iter_likes);
   525         injects @ distincts @ cases @ rec_likes @ rec_likes);
   526 
   526 
   527     fun derive_induct_iter_rec_thms_for_types ((wrap_ress, ctrss, iters, recs, xsss, ctr_defss,
   527     fun derive_induct_fold_rec_thms_for_types ((wrap_ress, ctrss, folds, recs, xsss, ctr_defss,
   528         iter_defs, rec_defs), lthy) =
   528         fold_defs, rec_defs), lthy) =
   529       let
   529       let
   530         val (((phis, phis'), us'), names_lthy) =
   530         val (((phis, phis'), us'), names_lthy) =
   531           lthy
   531           lthy
   532           |> mk_Frees' "P" (map mk_pred1T fpTs)
   532           |> mk_Frees' "P" (map mk_pred1T fpTs)
   533           ||>> Variable.variant_fixes fp_b_names;
   533           ||>> Variable.variant_fixes fp_b_names;
   613           end;
   613           end;
   614 
   614 
   615         (* TODO: Generate nicer names in case of clashes *)
   615         (* TODO: Generate nicer names in case of clashes *)
   616         val induct_cases = Datatype_Prop.indexify_names (maps (map base_name_of_ctr) ctrss);
   616         val induct_cases = Datatype_Prop.indexify_names (maps (map base_name_of_ctr) ctrss);
   617 
   617 
   618         val (iter_thmss, rec_thmss) =
   618         val (fold_thmss, rec_thmss) =
   619           let
   619           let
   620             val xctrss = map2 (map2 (curry Term.list_comb)) ctrss xsss;
   620             val xctrss = map2 (map2 (curry Term.list_comb)) ctrss xsss;
   621             val giters = map (lists_bmoc gss) iters;
   621             val gfolds = map (lists_bmoc gss) folds;
   622             val hrecs = map (lists_bmoc hss) recs;
   622             val hrecs = map (lists_bmoc hss) recs;
   623 
   623 
   624             fun mk_goal fss fiter_like xctr f xs fxs =
   624             fun mk_goal fss frec_like xctr f xs fxs =
   625               fold_rev (fold_rev Logic.all) (xs :: fss)
   625               fold_rev (fold_rev Logic.all) (xs :: fss)
   626                 (mk_Trueprop_eq (fiter_like $ xctr, Term.list_comb (f, fxs)));
   626                 (mk_Trueprop_eq (frec_like $ xctr, Term.list_comb (f, fxs)));
   627 
   627 
   628             fun build_call fiter_likes maybe_tick (T, U) =
   628             fun build_call frec_likes maybe_tick (T, U) =
   629               if T = U then
   629               if T = U then
   630                 id_const T
   630                 id_const T
   631               else
   631               else
   632                 (case find_index (curry (op =) T) fpTs of
   632                 (case find_index (curry (op =) T) fpTs of
   633                   ~1 => build_map (build_call fiter_likes maybe_tick) T U
   633                   ~1 => build_map (build_call frec_likes maybe_tick) T U
   634                 | j => maybe_tick (nth us j) (nth fiter_likes j));
   634                 | j => maybe_tick (nth us j) (nth frec_likes j));
   635 
   635 
   636             fun mk_U maybe_mk_prodT =
   636             fun mk_U maybe_mk_prodT =
   637               typ_subst (map2 (fn fpT => fn C => (fpT, maybe_mk_prodT fpT C)) fpTs Cs);
   637               typ_subst (map2 (fn fpT => fn C => (fpT, maybe_mk_prodT fpT C)) fpTs Cs);
   638 
   638 
   639             fun intr_calls fiter_likes maybe_cons maybe_tick maybe_mk_prodT (x as Free (_, T)) =
   639             fun intr_calls frec_likes maybe_cons maybe_tick maybe_mk_prodT (x as Free (_, T)) =
   640               if member (op =) fpTs T then
   640               if member (op =) fpTs T then
   641                 maybe_cons x [build_call fiter_likes (K I) (T, mk_U (K I) T) $ x]
   641                 maybe_cons x [build_call frec_likes (K I) (T, mk_U (K I) T) $ x]
   642               else if exists_fp_subtype T then
   642               else if exists_fp_subtype T then
   643                 [build_call fiter_likes maybe_tick (T, mk_U maybe_mk_prodT T) $ x]
   643                 [build_call frec_likes maybe_tick (T, mk_U maybe_mk_prodT T) $ x]
   644               else
   644               else
   645                 [x];
   645                 [x];
   646 
   646 
   647             val gxsss = map (map (maps (intr_calls giters (K I) (K I) (K I)))) xsss;
   647             val gxsss = map (map (maps (intr_calls gfolds (K I) (K I) (K I)))) xsss;
   648             val hxsss = map (map (maps (intr_calls hrecs cons tick (curry HOLogic.mk_prodT)))) xsss;
   648             val hxsss = map (map (maps (intr_calls hrecs cons tick (curry HOLogic.mk_prodT)))) xsss;
   649 
   649 
   650             val iter_goalss = map5 (map4 o mk_goal gss) giters xctrss gss xsss gxsss;
   650             val fold_goalss = map5 (map4 o mk_goal gss) gfolds xctrss gss xsss gxsss;
   651             val rec_goalss = map5 (map4 o mk_goal hss) hrecs xctrss hss xsss hxsss;
   651             val rec_goalss = map5 (map4 o mk_goal hss) hrecs xctrss hss xsss hxsss;
   652 
   652 
   653             val iter_tacss =
   653             val fold_tacss =
   654               map2 (map o mk_iter_like_tac pre_map_defs nesting_map_ids iter_defs) fp_iter_thms
   654               map2 (map o mk_rec_like_tac pre_map_defs nesting_map_ids fold_defs) fp_fold_thms
   655                 ctr_defss;
   655                 ctr_defss;
   656             val rec_tacss =
   656             val rec_tacss =
   657               map2 (map o mk_iter_like_tac pre_map_defs nesting_map_ids rec_defs) fp_rec_thms
   657               map2 (map o mk_rec_like_tac pre_map_defs nesting_map_ids rec_defs) fp_rec_thms
   658                 ctr_defss;
   658                 ctr_defss;
   659 
   659 
   660             fun prove goal tac = Skip_Proof.prove lthy [] [] goal (tac o #context);
   660             fun prove goal tac = Skip_Proof.prove lthy [] [] goal (tac o #context);
   661           in
   661           in
   662             (map2 (map2 prove) iter_goalss iter_tacss,
   662             (map2 (map2 prove) fold_goalss fold_tacss,
   663              map2 (map2 prove) rec_goalss rec_tacss)
   663              map2 (map2 prove) rec_goalss rec_tacss)
   664           end;
   664           end;
   665 
   665 
   666         val simp_thmss = mk_simp_thmss wrap_ress rec_thmss iter_thmss;
   666         val simp_thmss = mk_simp_thmss wrap_ress rec_thmss fold_thmss;
   667 
   667 
   668         val induct_case_names_attr = Attrib.internal (K (Rule_Cases.case_names induct_cases));
   668         val induct_case_names_attr = Attrib.internal (K (Rule_Cases.case_names induct_cases));
   669         fun induct_type_attr T_name = Attrib.internal (K (Induct.induct_type T_name));
   669         fun induct_type_attr T_name = Attrib.internal (K (Induct.induct_type T_name));
   670 
   670 
   671         (* TODO: Also note "recs", "simps", and "splits" if "nn > 1" (for compatibility with the
   671         (* TODO: Also note "recs", "simps", and "splits" if "nn > 1" (for compatibility with the
   676             ((Binding.qualify true fp_common_name (Binding.name thmN), attrs), [(thms, [])]));
   676             ((Binding.qualify true fp_common_name (Binding.name thmN), attrs), [(thms, [])]));
   677 
   677 
   678         val notes =
   678         val notes =
   679           [(inductN, map single induct_thms,
   679           [(inductN, map single induct_thms,
   680             fn T_name => [induct_case_names_attr, induct_type_attr T_name]),
   680             fn T_name => [induct_case_names_attr, induct_type_attr T_name]),
   681            (itersN, iter_thmss, K (Code.add_default_eqn_attrib :: simp_attrs)),
   681            (foldsN, fold_thmss, K (Code.add_default_eqn_attrib :: simp_attrs)),
   682            (recsN, rec_thmss, K (Code.add_default_eqn_attrib :: simp_attrs)),
   682            (recsN, rec_thmss, K (Code.add_default_eqn_attrib :: simp_attrs)),
   683            (simpsN, simp_thmss, K [])]
   683            (simpsN, simp_thmss, K [])]
   684           |> maps (fn (thmN, thmss, attrs) =>
   684           |> maps (fn (thmN, thmss, attrs) =>
   685             map3 (fn b => fn Type (T_name, _) => fn thms =>
   685             map3 (fn b => fn Type (T_name, _) => fn thms =>
   686               ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), attrs T_name),
   686               ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), attrs T_name),
   687                 [(thms, [])])) fp_bs fpTs thmss);
   687                 [(thms, [])])) fp_bs fpTs thmss);
   688       in
   688       in
   689         lthy |> Local_Theory.notes (common_notes @ notes) |> snd
   689         lthy |> Local_Theory.notes (common_notes @ notes) |> snd
   690       end;
   690       end;
   691 
   691 
   692     fun derive_coinduct_coiter_corec_thms_for_types ((wrap_ress, ctrss, coiters, corecs, _,
   692     fun derive_coinduct_unfold_corec_thms_for_types ((wrap_ress, ctrss, unfolds, corecs, _,
   693         ctr_defss, coiter_defs, corec_defs), lthy) =
   693         ctr_defss, unfold_defs, corec_defs), lthy) =
   694       let
   694       let
   695         val discss = map (map (mk_disc_or_sel As) o #1) wrap_ress;
   695         val discss = map (map (mk_disc_or_sel As) o #1) wrap_ress;
   696         val selsss = map #2 wrap_ress;
   696         val selsss = map #2 wrap_ress;
   697         val disc_thmsss = map #6 wrap_ress;
   697         val disc_thmsss = map #6 wrap_ress;
   698         val discIss = map #7 wrap_ress;
   698         val discIss = map #7 wrap_ress;
   712           end;
   712           end;
   713 
   713 
   714         fun mk_maybe_not pos = not pos ? HOLogic.mk_not;
   714         fun mk_maybe_not pos = not pos ? HOLogic.mk_not;
   715 
   715 
   716         val z = the_single zs;
   716         val z = the_single zs;
   717         val gcoiters = map (lists_bmoc pgss) coiters;
   717         val gunfolds = map (lists_bmoc pgss) unfolds;
   718         val hcorecs = map (lists_bmoc phss) corecs;
   718         val hcorecs = map (lists_bmoc phss) corecs;
   719 
   719 
   720         val (coiter_thmss, corec_thmss, safe_coiter_thmss, safe_corec_thmss) =
   720         val (unfold_thmss, corec_thmss, safe_unfold_thmss, safe_corec_thmss) =
   721           let
   721           let
   722             fun mk_goal pfss c cps fcoiter_like n k ctr m cfs' =
   722             fun mk_goal pfss c cps fcorec_like n k ctr m cfs' =
   723               fold_rev (fold_rev Logic.all) ([c] :: pfss)
   723               fold_rev (fold_rev Logic.all) ([c] :: pfss)
   724                 (Logic.list_implies (seq_conds (HOLogic.mk_Trueprop oo mk_maybe_not) n k cps,
   724                 (Logic.list_implies (seq_conds (HOLogic.mk_Trueprop oo mk_maybe_not) n k cps,
   725                    mk_Trueprop_eq (fcoiter_like $ c, Term.list_comb (ctr, take m cfs'))));
   725                    mk_Trueprop_eq (fcorec_like $ c, Term.list_comb (ctr, take m cfs'))));
   726 
   726 
   727             fun build_call fiter_likes maybe_tack (T, U) =
   727             fun build_call frec_likes maybe_tack (T, U) =
   728               if T = U then
   728               if T = U then
   729                 id_const T
   729                 id_const T
   730               else
   730               else
   731                 (case find_index (curry (op =) U) fpTs of
   731                 (case find_index (curry (op =) U) fpTs of
   732                   ~1 => build_map (build_call fiter_likes maybe_tack) T U
   732                   ~1 => build_map (build_call frec_likes maybe_tack) T U
   733                 | j => maybe_tack (nth cs j, nth us j) (nth fiter_likes j));
   733                 | j => maybe_tack (nth cs j, nth us j) (nth frec_likes j));
   734 
   734 
   735             fun mk_U maybe_mk_sumT =
   735             fun mk_U maybe_mk_sumT =
   736               typ_subst (map2 (fn C => fn fpT => (maybe_mk_sumT fpT C, fpT)) Cs fpTs);
   736               typ_subst (map2 (fn C => fn fpT => (maybe_mk_sumT fpT C, fpT)) Cs fpTs);
   737 
   737 
   738             fun intr_calls fiter_likes maybe_mk_sumT maybe_tack cqf =
   738             fun intr_calls frec_likes maybe_mk_sumT maybe_tack cqf =
   739               let val T = fastype_of cqf in
   739               let val T = fastype_of cqf in
   740                 if exists_subtype (member (op =) Cs) T then
   740                 if exists_subtype (member (op =) Cs) T then
   741                   build_call fiter_likes maybe_tack (T, mk_U maybe_mk_sumT T) $ cqf
   741                   build_call frec_likes maybe_tack (T, mk_U maybe_mk_sumT T) $ cqf
   742                 else
   742                 else
   743                   cqf
   743                   cqf
   744               end;
   744               end;
   745 
   745 
   746             val crgsss' = map (map (map (intr_calls gcoiters (K I) (K I)))) crgsss;
   746             val crgsss' = map (map (map (intr_calls gunfolds (K I) (K I)))) crgsss;
   747             val cshsss' = map (map (map (intr_calls hcorecs (curry mk_sumT) (tack z)))) cshsss;
   747             val cshsss' = map (map (map (intr_calls hcorecs (curry mk_sumT) (tack z)))) cshsss;
   748 
   748 
   749             val coiter_goalss =
   749             val unfold_goalss =
   750               map8 (map4 oooo mk_goal pgss) cs cpss gcoiters ns kss ctrss mss crgsss';
   750               map8 (map4 oooo mk_goal pgss) cs cpss gunfolds ns kss ctrss mss crgsss';
   751             val corec_goalss =
   751             val corec_goalss =
   752               map8 (map4 oooo mk_goal phss) cs cpss hcorecs ns kss ctrss mss cshsss';
   752               map8 (map4 oooo mk_goal phss) cs cpss hcorecs ns kss ctrss mss cshsss';
   753 
   753 
   754             val coiter_tacss =
   754             val unfold_tacss =
   755               map3 (map oo mk_coiter_like_tac coiter_defs nesting_map_ids) fp_iter_thms pre_map_defs
   755               map3 (map oo mk_corec_like_tac unfold_defs nesting_map_ids) fp_fold_thms pre_map_defs
   756                 ctr_defss;
   756                 ctr_defss;
   757             val corec_tacss =
   757             val corec_tacss =
   758               map3 (map oo mk_coiter_like_tac corec_defs nesting_map_ids) fp_rec_thms pre_map_defs
   758               map3 (map oo mk_corec_like_tac corec_defs nesting_map_ids) fp_rec_thms pre_map_defs
   759                 ctr_defss;
   759                 ctr_defss;
   760 
   760 
   761             fun prove goal tac =
   761             fun prove goal tac =
   762               Skip_Proof.prove lthy [] [] goal (tac o #context) |> Thm.close_derivation;
   762               Skip_Proof.prove lthy [] [] goal (tac o #context) |> Thm.close_derivation;
   763 
   763 
   764             val coiter_thmss = map2 (map2 prove) coiter_goalss coiter_tacss;
   764             val unfold_thmss = map2 (map2 prove) unfold_goalss unfold_tacss;
   765             val corec_thmss =
   765             val corec_thmss =
   766               map2 (map2 prove) corec_goalss corec_tacss
   766               map2 (map2 prove) corec_goalss corec_tacss
   767               |> map (map (unfold_defs lthy @{thms sum_case_if}));
   767               |> map (map (unfold_thms lthy @{thms sum_case_if}));
   768 
   768 
   769             val coiter_safesss = map2 (map2 (map2 (curry (op =)))) crgsss' crgsss;
   769             val unfold_safesss = map2 (map2 (map2 (curry (op =)))) crgsss' crgsss;
   770             val corec_safesss = map2 (map2 (map2 (curry (op =)))) cshsss' cshsss;
   770             val corec_safesss = map2 (map2 (map2 (curry (op =)))) cshsss' cshsss;
   771 
   771 
   772             val filter_safesss =
   772             val filter_safesss =
   773               map2 (map_filter (fn (safes, thm) => if forall I safes then SOME thm else NONE) oo
   773               map2 (map_filter (fn (safes, thm) => if forall I safes then SOME thm else NONE) oo
   774                 curry (op ~~));
   774                 curry (op ~~));
   775 
   775 
   776             val safe_coiter_thmss = filter_safesss coiter_safesss coiter_thmss;
   776             val safe_unfold_thmss = filter_safesss unfold_safesss unfold_thmss;
   777             val safe_corec_thmss = filter_safesss corec_safesss corec_thmss;
   777             val safe_corec_thmss = filter_safesss corec_safesss corec_thmss;
   778           in
   778           in
   779             (coiter_thmss, corec_thmss, safe_coiter_thmss, safe_corec_thmss)
   779             (unfold_thmss, corec_thmss, safe_unfold_thmss, safe_corec_thmss)
   780           end;
   780           end;
   781 
   781 
   782         val (disc_coiter_iff_thmss, disc_corec_iff_thmss) =
   782         val (disc_unfold_iff_thmss, disc_corec_iff_thmss) =
   783           let
   783           let
   784             fun mk_goal c cps fcoiter_like n k disc =
   784             fun mk_goal c cps fcorec_like n k disc =
   785               mk_Trueprop_eq (disc $ (fcoiter_like $ c),
   785               mk_Trueprop_eq (disc $ (fcorec_like $ c),
   786                 if n = 1 then @{const True}
   786                 if n = 1 then @{const True}
   787                 else Library.foldr1 HOLogic.mk_conj (seq_conds mk_maybe_not n k cps));
   787                 else Library.foldr1 HOLogic.mk_conj (seq_conds mk_maybe_not n k cps));
   788 
   788 
   789             val coiter_goalss = map6 (map2 oooo mk_goal) cs cpss gcoiters ns kss discss;
   789             val unfold_goalss = map6 (map2 oooo mk_goal) cs cpss gunfolds ns kss discss;
   790             val corec_goalss = map6 (map2 oooo mk_goal) cs cpss hcorecs ns kss discss;
   790             val corec_goalss = map6 (map2 oooo mk_goal) cs cpss hcorecs ns kss discss;
   791 
   791 
   792             fun mk_case_split' cp =
   792             fun mk_case_split' cp =
   793               Drule.instantiate' [] [SOME (certify lthy cp)] @{thm case_split};
   793               Drule.instantiate' [] [SOME (certify lthy cp)] @{thm case_split};
   794 
   794 
   795             val case_splitss' = map (map mk_case_split') cpss;
   795             val case_splitss' = map (map mk_case_split') cpss;
   796 
   796 
   797             val coiter_tacss =
   797             val unfold_tacss =
   798               map3 (map oo mk_disc_coiter_like_iff_tac) case_splitss' coiter_thmss disc_thmsss;
   798               map3 (map oo mk_disc_corec_like_iff_tac) case_splitss' unfold_thmss disc_thmsss;
   799             val corec_tacss =
   799             val corec_tacss =
   800               map3 (map oo mk_disc_coiter_like_iff_tac) case_splitss' corec_thmss disc_thmsss;
   800               map3 (map oo mk_disc_corec_like_iff_tac) case_splitss' corec_thmss disc_thmsss;
   801 
   801 
   802             fun prove goal tac =
   802             fun prove goal tac =
   803               Skip_Proof.prove lthy [] [] goal (tac o #context)
   803               Skip_Proof.prove lthy [] [] goal (tac o #context)
   804               |> Thm.close_derivation
   804               |> Thm.close_derivation
   805               |> singleton (Proof_Context.export names_lthy no_defs_lthy);
   805               |> singleton (Proof_Context.export names_lthy no_defs_lthy);
   806 
   806 
   807             fun proves [_] [_] = []
   807             fun proves [_] [_] = []
   808               | proves goals tacs = map2 prove goals tacs;
   808               | proves goals tacs = map2 prove goals tacs;
   809           in
   809           in
   810             (map2 proves coiter_goalss coiter_tacss,
   810             (map2 proves unfold_goalss unfold_tacss,
   811              map2 proves corec_goalss corec_tacss)
   811              map2 proves corec_goalss corec_tacss)
   812           end;
   812           end;
   813 
   813 
   814         fun mk_disc_coiter_like_thms coiter_likes discIs =
   814         fun mk_disc_corec_like_thms corec_likes discIs =
   815           map (op RS) (filter_out (is_triv_implies o snd) (coiter_likes ~~ discIs));
   815           map (op RS) (filter_out (is_triv_implies o snd) (corec_likes ~~ discIs));
   816 
   816 
   817         val disc_coiter_thmss = map2 mk_disc_coiter_like_thms coiter_thmss discIss;
   817         val disc_unfold_thmss = map2 mk_disc_corec_like_thms unfold_thmss discIss;
   818         val disc_corec_thmss = map2 mk_disc_coiter_like_thms corec_thmss discIss;
   818         val disc_corec_thmss = map2 mk_disc_corec_like_thms corec_thmss discIss;
   819 
   819 
   820         fun mk_sel_coiter_like_thm coiter_like_thm sel sel_thm =
   820         fun mk_sel_corec_like_thm corec_like_thm sel sel_thm =
   821           let
   821           let
   822             val (domT, ranT) = dest_funT (fastype_of sel);
   822             val (domT, ranT) = dest_funT (fastype_of sel);
   823             val arg_cong' =
   823             val arg_cong' =
   824               Drule.instantiate' (map (SOME o certifyT lthy) [domT, ranT])
   824               Drule.instantiate' (map (SOME o certifyT lthy) [domT, ranT])
   825                 [NONE, NONE, SOME (certify lthy sel)] arg_cong
   825                 [NONE, NONE, SOME (certify lthy sel)] arg_cong
   826               |> Thm.varifyT_global;
   826               |> Thm.varifyT_global;
   827             val sel_thm' = sel_thm RSN (2, trans);
   827             val sel_thm' = sel_thm RSN (2, trans);
   828           in
   828           in
   829             coiter_like_thm RS arg_cong' RS sel_thm'
   829             corec_like_thm RS arg_cong' RS sel_thm'
   830           end;
   830           end;
   831 
   831 
   832         fun mk_sel_coiter_like_thms coiter_likess =
   832         fun mk_sel_corec_like_thms corec_likess =
   833           map3 (map3 (map2 o mk_sel_coiter_like_thm)) coiter_likess selsss sel_thmsss |> map flat;
   833           map3 (map3 (map2 o mk_sel_corec_like_thm)) corec_likess selsss sel_thmsss |> map flat;
   834 
   834 
   835         val sel_coiter_thmss = mk_sel_coiter_like_thms coiter_thmss;
   835         val sel_unfold_thmss = mk_sel_corec_like_thms unfold_thmss;
   836         val sel_corec_thmss = mk_sel_coiter_like_thms corec_thmss;
   836         val sel_corec_thmss = mk_sel_corec_like_thms corec_thmss;
   837 
   837 
   838         fun zip_coiter_like_thms coiter_likes disc_coiter_likes sel_coiter_likes =
   838         fun zip_corec_like_thms corec_likes disc_corec_likes sel_corec_likes =
   839           coiter_likes @ disc_coiter_likes @ sel_coiter_likes;
   839           corec_likes @ disc_corec_likes @ sel_corec_likes;
   840 
   840 
   841         val simp_thmss =
   841         val simp_thmss =
   842           mk_simp_thmss wrap_ress
   842           mk_simp_thmss wrap_ress
   843             (map3 zip_coiter_like_thms safe_corec_thmss disc_corec_thmss sel_corec_thmss)
   843             (map3 zip_corec_like_thms safe_corec_thmss disc_corec_thmss sel_corec_thmss)
   844             (map3 zip_coiter_like_thms safe_coiter_thmss disc_coiter_thmss sel_coiter_thmss);
   844             (map3 zip_corec_like_thms safe_unfold_thmss disc_unfold_thmss sel_unfold_thmss);
   845 
   845 
   846         val anonymous_notes =
   846         val anonymous_notes =
   847           [(flat safe_coiter_thmss @ flat safe_corec_thmss, simp_attrs)]
   847           [(flat safe_unfold_thmss @ flat safe_corec_thmss, simp_attrs)]
   848           |> map (fn (thms, attrs) => ((Binding.empty, attrs), [(thms, [])]));
   848           |> map (fn (thms, attrs) => ((Binding.empty, attrs), [(thms, [])]));
   849 
   849 
   850         val common_notes =
   850         val common_notes =
   851           (if nn > 1 then [(coinductN, [coinduct_thm], [])] (* FIXME: attribs *) else [])
   851           (if nn > 1 then [(coinductN, [coinduct_thm], [])] (* FIXME: attribs *) else [])
   852           |> map (fn (thmN, thms, attrs) =>
   852           |> map (fn (thmN, thms, attrs) =>
   853             ((Binding.qualify true fp_common_name (Binding.name thmN), attrs), [(thms, [])]));
   853             ((Binding.qualify true fp_common_name (Binding.name thmN), attrs), [(thms, [])]));
   854 
   854 
   855         val notes =
   855         val notes =
   856           [(coinductN, map single coinduct_thms, []), (* FIXME: attribs *)
   856           [(coinductN, map single coinduct_thms, []), (* FIXME: attribs *)
   857            (coitersN, coiter_thmss, []),
   857            (unfoldsN, unfold_thmss, []),
   858            (corecsN, corec_thmss, []),
   858            (corecsN, corec_thmss, []),
   859            (disc_coiter_iffN, disc_coiter_iff_thmss, simp_attrs),
   859            (disc_unfold_iffN, disc_unfold_iff_thmss, simp_attrs),
   860            (disc_coitersN, disc_coiter_thmss, simp_attrs),
   860            (disc_unfoldsN, disc_unfold_thmss, simp_attrs),
   861            (disc_corec_iffN, disc_corec_iff_thmss, simp_attrs),
   861            (disc_corec_iffN, disc_corec_iff_thmss, simp_attrs),
   862            (disc_corecsN, disc_corec_thmss, simp_attrs),
   862            (disc_corecsN, disc_corec_thmss, simp_attrs),
   863            (sel_coitersN, sel_coiter_thmss, simp_attrs),
   863            (sel_unfoldsN, sel_unfold_thmss, simp_attrs),
   864            (sel_corecsN, sel_corec_thmss, simp_attrs),
   864            (sel_corecsN, sel_corec_thmss, simp_attrs),
   865            (simpsN, simp_thmss, [])]
   865            (simpsN, simp_thmss, [])]
   866           |> maps (fn (thmN, thmss, attrs) =>
   866           |> maps (fn (thmN, thmss, attrs) =>
   867             map_filter (fn (_, []) => NONE | (b, thms) =>
   867             map_filter (fn (_, []) => NONE | (b, thms) =>
   868               SOME ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), attrs),
   868               SOME ((Binding.qualify true (Binding.name_of b) (Binding.name thmN), attrs),
   869                 [(thms, [])])) (fp_bs ~~ thmss));
   869                 [(thms, [])])) (fp_bs ~~ thmss));
   870       in
   870       in
   871         lthy |> Local_Theory.notes (anonymous_notes @ common_notes @ notes) |> snd
   871         lthy |> Local_Theory.notes (anonymous_notes @ common_notes @ notes) |> snd
   872       end;
   872       end;
   873 
   873 
   874     fun wrap_types_and_define_iter_likes ((wraps, define_iter_likess), lthy) =
   874     fun wrap_types_and_define_rec_likes ((wraps, define_rec_likess), lthy) =
   875       fold_map2 (curry (op o)) define_iter_likess wraps lthy |>> split_list8
   875       fold_map2 (curry (op o)) define_rec_likess wraps lthy |>> split_list8
   876 
   876 
   877     val lthy' = lthy
   877     val lthy' = lthy
   878       |> fold_map define_ctrs_case_for_type (fp_bs ~~ fpTs ~~ Cs ~~ ctors ~~ dtors ~~ fp_iters ~~
   878       |> fold_map define_ctrs_case_for_type (fp_bs ~~ fpTs ~~ Cs ~~ ctors ~~ dtors ~~ fp_folds ~~
   879         fp_recs ~~ ctor_dtors ~~ dtor_ctors ~~ ctor_injects ~~ ns ~~ kss ~~ mss ~~ ctr_bindingss ~~
   879         fp_recs ~~ ctor_dtors ~~ dtor_ctors ~~ ctor_injects ~~ ns ~~ kss ~~ mss ~~ ctr_bindingss ~~
   880         ctr_mixfixess ~~ ctr_Tsss ~~ disc_bindingss ~~ sel_bindingsss ~~ raw_sel_defaultsss)
   880         ctr_mixfixess ~~ ctr_Tsss ~~ disc_bindingss ~~ sel_bindingsss ~~ raw_sel_defaultsss)
   881       |>> split_list |> wrap_types_and_define_iter_likes
   881       |>> split_list |> wrap_types_and_define_rec_likes
   882       |> (if lfp then derive_induct_iter_rec_thms_for_types
   882       |> (if lfp then derive_induct_fold_rec_thms_for_types
   883           else derive_coinduct_coiter_corec_thms_for_types);
   883           else derive_coinduct_unfold_corec_thms_for_types);
   884 
   884 
   885     val timer = time (timer ("Constructors, discriminators, selectors, etc., for the new " ^
   885     val timer = time (timer ("Constructors, discriminators, selectors, etc., for the new " ^
   886       (if lfp then "" else "co") ^ "datatype"));
   886       (if lfp then "" else "co") ^ "datatype"));
   887   in
   887   in
   888     timer; lthy'
   888     timer; lthy'