src/HOL/BNF/Tools/bnf_fp_rec_sugar_util.ML
author blanchet
Thu, 19 Sep 2013 01:09:25 +0200
changeset 54864 1d88a7ee4e3e
parent 54863 d41a30db83d9
child 54866 b9d727a767ea
permissions -rw-r--r--
split functionality into two functions to avoid redoing work over and over
     1 (*  Title:      HOL/BNF/Tools/bnf_fp_rec_sugar_util.ML
     2     Author:     Lorenz Panny, TU Muenchen
     3     Author:     Jasmin Blanchette, TU Muenchen
     4     Copyright   2013
     5 
     6 Library for recursor and corecursor sugar.
     7 *)
     8 
     9 signature BNF_FP_REC_SUGAR_UTIL =
    10 sig
    11   datatype rec_call =
    12     No_Rec of int |
    13     Direct_Rec of int (*before*) * int (*after*) |
    14     Indirect_Rec of int
    15 
    16   datatype corec_call =
    17     Dummy_No_Corec of int |
    18     No_Corec of int |
    19     Direct_Corec of int (*stop?*) * int (*end*) * int (*continue*) |
    20     Indirect_Corec of int
    21 
    22   type rec_ctr_spec =
    23     {ctr: term,
    24      offset: int,
    25      calls: rec_call list,
    26      rec_thm: thm}
    27 
    28   type corec_ctr_spec =
    29     {ctr: term,
    30      disc: term,
    31      sels: term list,
    32      pred: int option,
    33      calls: corec_call list,
    34      discI: thm,
    35      sel_thms: thm list,
    36      collapse: thm,
    37      corec_thm: thm,
    38      disc_corec: thm,
    39      sel_corecs: thm list}
    40 
    41   type rec_spec =
    42     {recx: term,
    43      nested_map_idents: thm list,
    44      nested_map_comps: thm list,
    45      ctr_specs: rec_ctr_spec list}
    46 
    47   type corec_spec =
    48     {corec: term,
    49      nested_maps: thm list,
    50      nested_map_idents: thm list,
    51      nested_map_comps: thm list,
    52      ctr_specs: corec_ctr_spec list}
    53 
    54   val massage_indirect_rec_call: Proof.context -> (term -> bool) -> (typ -> typ -> term -> term) ->
    55     typ list -> term -> term -> term -> term
    56   val massage_direct_corec_call: Proof.context -> (term -> bool) -> (term -> term) -> typ -> term ->
    57     term
    58   val massage_indirect_corec_call: Proof.context -> (term -> bool) ->
    59     (typ -> typ -> term -> term) -> typ list -> typ -> term -> term
    60   val expand_corec_code_rhs: Proof.context -> (term -> bool) -> typ list -> term -> term
    61   val massage_corec_code_rhs: Proof.context -> (term -> term list -> term) -> typ -> term -> term
    62   val rec_specs_of: binding list -> typ list -> typ list -> (term -> int list) ->
    63     ((term * term list list) list) list -> local_theory ->
    64     (bool * rec_spec list * typ list * thm * thm list) * local_theory
    65   val corec_specs_of: binding list -> typ list -> typ list -> (term -> int list) ->
    66     ((term * term list list) list) list -> local_theory ->
    67     (bool * corec_spec list * typ list * thm * thm * thm list * thm list) * local_theory
    68 end;
    69 
    70 structure BNF_FP_Rec_Sugar_Util : BNF_FP_REC_SUGAR_UTIL =
    71 struct
    72 
    73 open BNF_Util
    74 open BNF_Def
    75 open BNF_Ctr_Sugar
    76 open BNF_FP_Util
    77 open BNF_FP_Def_Sugar
    78 open BNF_FP_N2M_Sugar
    79 
    80 datatype rec_call =
    81   No_Rec of int |
    82   Direct_Rec of int * int |
    83   Indirect_Rec of int;
    84 
    85 datatype corec_call =
    86   Dummy_No_Corec of int |
    87   No_Corec of int |
    88   Direct_Corec of int * int * int |
    89   Indirect_Corec of int;
    90 
    91 type rec_ctr_spec =
    92   {ctr: term,
    93    offset: int,
    94    calls: rec_call list,
    95    rec_thm: thm};
    96 
    97 type corec_ctr_spec =
    98   {ctr: term,
    99    disc: term,
   100    sels: term list,
   101    pred: int option,
   102    calls: corec_call list,
   103    discI: thm,
   104    sel_thms: thm list,
   105    collapse: thm,
   106    corec_thm: thm,
   107    disc_corec: thm,
   108    sel_corecs: thm list};
   109 
   110 type rec_spec =
   111   {recx: term,
   112    nested_map_idents: thm list,
   113    nested_map_comps: thm list,
   114    ctr_specs: rec_ctr_spec list};
   115 
   116 type corec_spec =
   117   {corec: term,
   118    nested_maps: thm list,
   119    nested_map_idents: thm list,
   120    nested_map_comps: thm list,
   121    ctr_specs: corec_ctr_spec list};
   122 
   123 val id_def = @{thm id_def};
   124 
   125 exception AINT_NO_MAP of term;
   126 
   127 fun ill_formed_rec_call ctxt t =
   128   error ("Ill-formed recursive call: " ^ quote (Syntax.string_of_term ctxt t));
   129 fun ill_formed_corec_call ctxt t =
   130   error ("Ill-formed corecursive call: " ^ quote (Syntax.string_of_term ctxt t));
   131 fun invalid_map ctxt t =
   132   error ("Invalid map function in " ^ quote (Syntax.string_of_term ctxt t));
   133 fun unexpected_rec_call ctxt t =
   134   error ("Unexpected recursive call: " ^ quote (Syntax.string_of_term ctxt t));
   135 fun unexpected_corec_call ctxt t =
   136   error ("Unexpected corecursive call: " ^ quote (Syntax.string_of_term ctxt t));
   137 
   138 fun factor_out_types ctxt massage destU U T =
   139   (case try destU U of
   140     SOME (U1, U2) => if U1 = T then massage T U2 else invalid_map ctxt
   141   | NONE => invalid_map ctxt);
   142 
   143 fun map_flattened_map_args ctxt s map_args fs =
   144   let
   145     val flat_fs = flatten_type_args_of_bnf (the (bnf_of ctxt s)) Term.dummy fs;
   146     val flat_fs' = map_args flat_fs;
   147   in
   148     permute_like (op aconv) flat_fs fs flat_fs'
   149   end;
   150 
   151 fun massage_indirect_rec_call ctxt has_call massage_unapplied_direct_call bound_Ts y y' =
   152   let
   153     val typof = curry fastype_of1 bound_Ts;
   154     val build_map_fst = build_map ctxt (fst_const o fst);
   155 
   156     val yT = typof y;
   157     val yU = typof y';
   158 
   159     fun y_of_y' () = build_map_fst (yU, yT) $ y';
   160     val elim_y = Term.map_aterms (fn t => if t = y then y_of_y' () else t);
   161 
   162     fun check_and_massage_unapplied_direct_call U T t =
   163       if has_call t then
   164         factor_out_types ctxt massage_unapplied_direct_call HOLogic.dest_prodT U T t
   165       else
   166         HOLogic.mk_comp (t, build_map_fst (U, T));
   167 
   168     fun massage_map (Type (_, Us)) (Type (s, Ts)) t =
   169         (case try (dest_map ctxt s) t of
   170           SOME (map0, fs) =>
   171           let
   172             val Type (_, ran_Ts) = range_type (typof t);
   173             val map' = mk_map (length fs) Us ran_Ts map0;
   174             val fs' = map_flattened_map_args ctxt s (map3 massage_map_or_map_arg Us Ts) fs;
   175           in
   176             list_comb (map', fs')
   177           end
   178         | NONE => raise AINT_NO_MAP t)
   179       | massage_map _ _ t = raise AINT_NO_MAP t
   180     and massage_map_or_map_arg U T t =
   181       if T = U then
   182         if has_call t then unexpected_rec_call ctxt t else t
   183       else
   184         massage_map U T t
   185         handle AINT_NO_MAP _ => check_and_massage_unapplied_direct_call U T t;
   186 
   187     fun massage_call (t as t1 $ t2) =
   188         if t2 = y then
   189           massage_map yU yT (elim_y t1) $ y'
   190           handle AINT_NO_MAP t' => invalid_map ctxt t'
   191         else
   192           ill_formed_rec_call ctxt t
   193       | massage_call t = if t = y then y_of_y' () else ill_formed_rec_call ctxt t;
   194   in
   195     massage_call
   196   end;
   197 
   198 fun massage_let_and_if ctxt has_call massage_leaf U =
   199   let
   200     val check_cond = ((not o has_call) orf unexpected_corec_call ctxt);
   201     fun massage_rec t =
   202       (case Term.strip_comb t of
   203         (Const (@{const_name Let}, _), [arg1, arg2]) => massage_rec (betapply (arg2, arg1))
   204       | (Const (@{const_name If}, _), arg :: args) =>
   205         list_comb (If_const U $ tap check_cond arg, map massage_rec args)
   206       | _ => massage_leaf t)
   207   in
   208     massage_rec
   209   end;
   210 
   211 fun massage_direct_corec_call ctxt has_call massage_direct_call U t =
   212   massage_let_and_if ctxt has_call massage_direct_call U t;
   213 
   214 fun massage_indirect_corec_call ctxt has_call massage_direct_call bound_Ts U t =
   215   let
   216     val typof = curry fastype_of1 bound_Ts;
   217     val build_map_Inl = build_map ctxt (uncurry Inl_const o dest_sumT o snd)
   218 
   219     fun check_and_massage_direct_call U T t =
   220       if has_call t then factor_out_types ctxt massage_direct_call dest_sumT U T t
   221       else build_map_Inl (T, U) $ t;
   222 
   223     fun check_and_massage_unapplied_direct_call U T t =
   224       let val var = Var ((Name.uu, Term.maxidx_of_term t + 1), domain_type (typof t)) in
   225         Term.lambda var (check_and_massage_direct_call U T (t $ var))
   226       end;
   227 
   228     fun massage_map (Type (_, Us)) (Type (s, Ts)) t =
   229         (case try (dest_map ctxt s) t of
   230           SOME (map0, fs) =>
   231           let
   232             val Type (_, dom_Ts) = domain_type (typof t);
   233             val map' = mk_map (length fs) dom_Ts Us map0;
   234             val fs' = map_flattened_map_args ctxt s (map3 massage_map_or_map_arg Us Ts) fs;
   235           in
   236             list_comb (map', fs')
   237           end
   238         | NONE => raise AINT_NO_MAP t)
   239       | massage_map _ _ t = raise AINT_NO_MAP t
   240     and massage_map_or_map_arg U T t =
   241       if T = U then
   242         if has_call t then unexpected_corec_call ctxt t else t
   243       else
   244         massage_map U T t
   245         handle AINT_NO_MAP _ => check_and_massage_unapplied_direct_call U T t;
   246 
   247     fun massage_call U T =
   248       massage_let_and_if ctxt has_call (fn t =>
   249         (case U of
   250           Type (s, Us) =>
   251           (case try (dest_ctr ctxt s) t of
   252             SOME (f, args) =>
   253             let val f' = mk_ctr Us f in
   254               list_comb (f', map3 massage_call (binder_types (typof f')) (map typof args) args)
   255             end
   256           | NONE =>
   257             (case t of
   258               t1 $ t2 =>
   259               (if has_call t2 then
   260                 check_and_massage_direct_call U T t
   261               else
   262                 massage_map U T t1 $ t2
   263                 handle AINT_NO_MAP _ => check_and_massage_direct_call U T t)
   264             | _ => check_and_massage_direct_call U T t))
   265         | _ => ill_formed_corec_call ctxt t)) U
   266   in
   267     massage_call U (typof t) t
   268   end;
   269 
   270 fun expand_ctr_term ctxt s Ts t =
   271   (case fp_sugar_of ctxt s of
   272     SOME fp_sugar =>
   273     let
   274       val T = Type (s, Ts);
   275       val x = Bound 0;
   276       val {ctrs = ctrs0, discs = discs0, selss = selss0, ...} = of_fp_sugar #ctr_sugars fp_sugar;
   277       val ctrs = map (mk_ctr Ts) ctrs0;
   278       val discs = map (mk_disc_or_sel Ts) discs0;
   279       val selss = map (map (mk_disc_or_sel Ts)) selss0;
   280       val xdiscs = map (rapp x) discs;
   281       val xselss = map (map (rapp x)) selss;
   282       val xsel_ctrs = map2 (curry Term.list_comb) ctrs xselss;
   283       val xif = mk_IfN T xdiscs xsel_ctrs;
   284     in
   285       Const (@{const_name Let}, T --> (T --> T) --> T) $ t $ Abs (Name.uu, T, xif)
   286     end
   287   | NONE => raise Fail "expand_ctr_term");
   288 
   289 fun expand_corec_code_rhs ctxt has_call bound_Ts t =
   290   (case fastype_of1 (bound_Ts, t) of
   291     T as Type (s, Ts) =>
   292     massage_let_and_if ctxt has_call (fn t =>
   293       if can (dest_ctr ctxt s) t then t
   294       else massage_let_and_if ctxt has_call I T (expand_ctr_term ctxt s Ts t)) T t
   295   | _ => raise Fail "expand_corec_code_rhs");
   296 
   297 fun massage_corec_code_rhs ctxt massage_ctr =
   298   massage_let_and_if ctxt (K false) (uncurry massage_ctr o Term.strip_comb);
   299 
   300 fun indexed xs h = let val h' = h + length xs in (h upto h' - 1, h') end;
   301 fun indexedd xss = fold_map indexed xss;
   302 fun indexeddd xsss = fold_map indexedd xsss;
   303 fun indexedddd xssss = fold_map indexeddd xssss;
   304 
   305 fun find_index_eq hs h = find_index (curry (op =) h) hs;
   306 
   307 (*FIXME: remove special cases for products and sum once they are registered as datatypes*)
   308 fun map_thms_of_typ ctxt (Type (s, _)) =
   309     if s = @{type_name prod} then
   310       @{thms map_pair_simp}
   311     else if s = @{type_name sum} then
   312       @{thms sum_map.simps}
   313     else
   314       (case fp_sugar_of ctxt s of
   315         SOME {index, mapss, ...} => nth mapss index
   316       | NONE => [])
   317   | map_thms_of_typ _ _ = [];
   318 
   319 val lose_co_rec = false (*FIXME: try true?*);
   320 
   321 fun rec_specs_of bs arg_Ts res_Ts get_indices callssss0 lthy =
   322   let
   323     val thy = Proof_Context.theory_of lthy;
   324 
   325     val ((nontriv, missing_arg_Ts, perm0_kks,
   326           fp_sugars as {nested_bnfs, fp_res = {xtor_co_iterss = ctor_iters1 :: _, ...},
   327             co_inducts = [induct_thm], ...} :: _), lthy') =
   328       nested_to_mutual_fps lose_co_rec Least_FP bs arg_Ts get_indices callssss0 lthy;
   329 
   330     val perm_fp_sugars = sort (int_ord o pairself #index) fp_sugars;
   331 
   332     val indices = map #index fp_sugars;
   333     val perm_indices = map #index perm_fp_sugars;
   334 
   335     val perm_ctrss = map (#ctrs o of_fp_sugar #ctr_sugars) perm_fp_sugars;
   336     val perm_ctr_Tsss = map (map (binder_types o fastype_of)) perm_ctrss;
   337     val perm_fpTs = map (body_type o fastype_of o hd) perm_ctrss;
   338 
   339     val nn0 = length arg_Ts;
   340     val nn = length perm_fpTs;
   341     val kks = 0 upto nn - 1;
   342     val perm_ns = map length perm_ctr_Tsss;
   343     val perm_mss = map (map length) perm_ctr_Tsss;
   344 
   345     val perm_Cs = map (body_type o fastype_of o co_rec_of o of_fp_sugar (#xtor_co_iterss o #fp_res))
   346       perm_fp_sugars;
   347     val perm_fun_arg_Tssss =
   348       mk_iter_fun_arg_types perm_ctr_Tsss perm_ns perm_mss (co_rec_of ctor_iters1);
   349 
   350     fun unpermute0 perm0_xs = permute_like (op =) perm0_kks kks perm0_xs;
   351     fun unpermute perm_xs = permute_like (op =) perm_indices indices perm_xs;
   352 
   353     val induct_thms = unpermute0 (conj_dests nn induct_thm);
   354 
   355     val fpTs = unpermute perm_fpTs;
   356     val Cs = unpermute perm_Cs;
   357 
   358     val As_rho = tvar_subst thy (take nn0 fpTs) arg_Ts;
   359     val Cs_rho = map (fst o dest_TVar) Cs ~~ pad_list HOLogic.unitT nn res_Ts;
   360 
   361     val substA = Term.subst_TVars As_rho;
   362     val substAT = Term.typ_subst_TVars As_rho;
   363     val substCT = Term.typ_subst_TVars Cs_rho;
   364 
   365     val perm_Cs' = map substCT perm_Cs;
   366 
   367     fun offset_of_ctr 0 _ = 0
   368       | offset_of_ctr n ({ctrs, ...} :: ctr_sugars) =
   369         length ctrs + offset_of_ctr (n - 1) ctr_sugars;
   370 
   371     fun call_of [i] [T] = (if exists_subtype_in Cs T then Indirect_Rec else No_Rec) i
   372       | call_of [i, i'] _ = Direct_Rec (i, i');
   373 
   374     fun mk_ctr_spec ctr offset fun_arg_Tss rec_thm =
   375       let
   376         val (fun_arg_hss, _) = indexedd fun_arg_Tss 0;
   377         val fun_arg_hs = flat_rec_arg_args fun_arg_hss;
   378         val fun_arg_iss = map (map (find_index_eq fun_arg_hs)) fun_arg_hss;
   379       in
   380         {ctr = substA ctr, offset = offset, calls = map2 call_of fun_arg_iss fun_arg_Tss,
   381          rec_thm = rec_thm}
   382       end;
   383 
   384     fun mk_ctr_specs index ctr_sugars iter_thmsss =
   385       let
   386         val ctrs = #ctrs (nth ctr_sugars index);
   387         val rec_thmss = co_rec_of (nth iter_thmsss index);
   388         val k = offset_of_ctr index ctr_sugars;
   389         val n = length ctrs;
   390       in
   391         map4 mk_ctr_spec ctrs (k upto k + n - 1) (nth perm_fun_arg_Tssss index) rec_thmss
   392       end;
   393 
   394     fun mk_spec {T, index, ctr_sugars, co_iterss = iterss, co_iter_thmsss = iter_thmsss, ...} =
   395       {recx = mk_co_iter thy Least_FP (substAT T) perm_Cs' (co_rec_of (nth iterss index)),
   396        nested_map_idents = map (unfold_thms lthy [id_def] o map_id0_of_bnf) nested_bnfs,
   397        nested_map_comps = map map_comp_of_bnf nested_bnfs,
   398        ctr_specs = mk_ctr_specs index ctr_sugars iter_thmsss};
   399   in
   400     ((nontriv, map mk_spec fp_sugars, missing_arg_Ts, induct_thm, induct_thms), lthy')
   401   end;
   402 
   403 fun corec_specs_of bs arg_Ts res_Ts get_indices callssss0 lthy =
   404   let
   405     val thy = Proof_Context.theory_of lthy;
   406 
   407     val ((nontriv, missing_res_Ts, perm0_kks,
   408           fp_sugars as {nested_bnfs, fp_res = {xtor_co_iterss = dtor_coiters1 :: _, ...},
   409             co_inducts = coinduct_thms, ...} :: _), lthy') =
   410       nested_to_mutual_fps lose_co_rec Greatest_FP bs res_Ts get_indices callssss0 lthy;
   411 
   412     val perm_fp_sugars = sort (int_ord o pairself #index) fp_sugars;
   413 
   414     val indices = map #index fp_sugars;
   415     val perm_indices = map #index perm_fp_sugars;
   416 
   417     val perm_ctrss = map (#ctrs o of_fp_sugar #ctr_sugars) perm_fp_sugars;
   418     val perm_ctr_Tsss = map (map (binder_types o fastype_of)) perm_ctrss;
   419     val perm_fpTs = map (body_type o fastype_of o hd) perm_ctrss;
   420 
   421     val nn0 = length res_Ts;
   422     val nn = length perm_fpTs;
   423     val kks = 0 upto nn - 1;
   424     val perm_ns = map length perm_ctr_Tsss;
   425 
   426     val perm_Cs = map (domain_type o body_fun_type o fastype_of o co_rec_of o
   427       of_fp_sugar (#xtor_co_iterss o #fp_res)) perm_fp_sugars;
   428     val (perm_p_Tss, (perm_q_Tssss, _, perm_f_Tssss, _)) =
   429       mk_coiter_fun_arg_types perm_ctr_Tsss perm_Cs perm_ns (co_rec_of dtor_coiters1);
   430 
   431     val (perm_p_hss, h) = indexedd perm_p_Tss 0;
   432     val (perm_q_hssss, h') = indexedddd perm_q_Tssss h;
   433     val (perm_f_hssss, _) = indexedddd perm_f_Tssss h';
   434 
   435     val fun_arg_hs =
   436       flat (map3 flat_corec_preds_predsss_gettersss perm_p_hss perm_q_hssss perm_f_hssss);
   437 
   438     fun unpermute0 perm0_xs = permute_like (op =) perm0_kks kks perm0_xs;
   439     fun unpermute perm_xs = permute_like (op =) perm_indices indices perm_xs;
   440 
   441     val coinduct_thmss = map (unpermute0 o conj_dests nn) coinduct_thms;
   442 
   443     val p_iss = map (map (find_index_eq fun_arg_hs)) (unpermute perm_p_hss);
   444     val q_issss = map (map (map (map (find_index_eq fun_arg_hs)))) (unpermute perm_q_hssss);
   445     val f_issss = map (map (map (map (find_index_eq fun_arg_hs)))) (unpermute perm_f_hssss);
   446 
   447     val f_Tssss = unpermute perm_f_Tssss;
   448     val fpTs = unpermute perm_fpTs;
   449     val Cs = unpermute perm_Cs;
   450 
   451     val As_rho = tvar_subst thy (take nn0 fpTs) res_Ts;
   452     val Cs_rho = map (fst o dest_TVar) Cs ~~ pad_list HOLogic.unitT nn arg_Ts;
   453 
   454     val substA = Term.subst_TVars As_rho;
   455     val substAT = Term.typ_subst_TVars As_rho;
   456     val substCT = Term.typ_subst_TVars Cs_rho;
   457 
   458     val perm_Cs' = map substCT perm_Cs;
   459 
   460     fun call_of nullary [] [g_i] [Type (@{type_name fun}, [_, T])] =
   461         (if exists_subtype_in Cs T then Indirect_Corec
   462          else if nullary then Dummy_No_Corec
   463          else No_Corec) g_i
   464       | call_of _ [q_i] [g_i, g_i'] _ = Direct_Corec (q_i, g_i, g_i');
   465 
   466     fun mk_ctr_spec ctr disc sels p_ho q_iss f_iss f_Tss discI sel_thms collapse corec_thm
   467         disc_corec sel_corecs =
   468       let val nullary = not (can dest_funT (fastype_of ctr)) in
   469         {ctr = substA ctr, disc = substA disc, sels = map substA sels, pred = p_ho,
   470          calls = map3 (call_of nullary) q_iss f_iss f_Tss, discI = discI, sel_thms = sel_thms,
   471          collapse = collapse, corec_thm = corec_thm, disc_corec = disc_corec,
   472          sel_corecs = sel_corecs}
   473       end;
   474 
   475     fun mk_ctr_specs index ctr_sugars p_is q_isss f_isss f_Tsss coiter_thmsss disc_coitersss
   476         sel_coiterssss =
   477       let
   478         val ctrs = #ctrs (nth ctr_sugars index);
   479         val discs = #discs (nth ctr_sugars index);
   480         val selss = #selss (nth ctr_sugars index);
   481         val p_ios = map SOME p_is @ [NONE];
   482         val discIs = #discIs (nth ctr_sugars index);
   483         val sel_thmss = #sel_thmss (nth ctr_sugars index);
   484         val collapses = #collapses (nth ctr_sugars index);
   485         val corec_thms = co_rec_of (nth coiter_thmsss index);
   486         val disc_corecs = (case co_rec_of (nth disc_coitersss index) of [] => [TrueI]
   487           | thms => thms);
   488         val sel_corecss = co_rec_of (nth sel_coiterssss index);
   489       in
   490         map13 mk_ctr_spec ctrs discs selss p_ios q_isss f_isss f_Tsss discIs sel_thmss collapses
   491           corec_thms disc_corecs sel_corecss
   492       end;
   493 
   494     fun mk_spec {T, index, ctr_sugars, co_iterss = coiterss, co_iter_thmsss = coiter_thmsss,
   495           disc_co_itersss = disc_coitersss, sel_co_iterssss = sel_coiterssss, ...}
   496         p_is q_isss f_isss f_Tsss =
   497       {corec = mk_co_iter thy Greatest_FP (substAT T) perm_Cs' (co_rec_of (nth coiterss index)),
   498        nested_maps = maps (map_thms_of_typ lthy o T_of_bnf) nested_bnfs,
   499        nested_map_idents = map (unfold_thms lthy [id_def] o map_id0_of_bnf) nested_bnfs,
   500        nested_map_comps = map map_comp_of_bnf nested_bnfs,
   501        ctr_specs = mk_ctr_specs index ctr_sugars p_is q_isss f_isss f_Tsss coiter_thmsss
   502          disc_coitersss sel_coiterssss};
   503   in
   504     ((nontriv, map5 mk_spec fp_sugars p_iss q_issss f_issss f_Tssss, missing_res_Ts,
   505       co_induct_of coinduct_thms, strong_co_induct_of coinduct_thms, co_induct_of coinduct_thmss,
   506       strong_co_induct_of coinduct_thmss), lthy')
   507   end;
   508 
   509 end;