src/HOL/Tools/BNF/bnf_lfp_size.ML
changeset 58179 2de7b0313de3
parent 58128 43a1ba26a8cb
child 58180 95397823f39e
equal deleted inserted replaced
58178:695ba3101b37 58179:2de7b0313de3
     7 
     7 
     8 signature BNF_LFP_SIZE =
     8 signature BNF_LFP_SIZE =
     9 sig
     9 sig
    10   val register_size: string -> string -> thm list -> thm list -> local_theory -> local_theory
    10   val register_size: string -> string -> thm list -> thm list -> local_theory -> local_theory
    11   val register_size_global: string -> string -> thm list -> thm list -> theory -> theory
    11   val register_size_global: string -> string -> thm list -> thm list -> theory -> theory
    12   val lookup_size: Proof.context -> string -> (string * (thm list * thm list)) option
    12   val size_of: Proof.context -> string -> (string * (thm list * thm list)) option
    13   val lookup_size_global: theory -> string -> (string * (thm list * thm list)) option
    13   val size_of_global: theory -> string -> (string * (thm list * thm list)) option
    14   val generate_lfp_size: BNF_FP_Util.fp_sugar list -> local_theory -> local_theory
       
    15 end;
    14 end;
    16 
    15 
    17 structure BNF_LFP_Size : BNF_LFP_SIZE =
    16 structure BNF_LFP_Size : BNF_LFP_SIZE =
    18 struct
    17 struct
    19 
    18 
    20 open BNF_Util
    19 open BNF_Util
    21 open BNF_Tactics
    20 open BNF_Tactics
    22 open BNF_Def
    21 open BNF_Def
    23 open BNF_FP_Util
    22 open BNF_FP_Util
       
    23 open BNF_FP_Def_Sugar
    24 
    24 
    25 val size_N = "size_"
    25 val size_N = "size_"
    26 
    26 
    27 val rec_o_mapN = "rec_o_map"
    27 val rec_o_mapN = "rec_o_map"
    28 val sizeN = "size"
    28 val sizeN = "size"
    44   Context.proof_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps)))));
    44   Context.proof_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps)))));
    45 
    45 
    46 fun register_size_global T_name size_name size_simps size_o_maps =
    46 fun register_size_global T_name size_name size_simps size_o_maps =
    47   Context.theory_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps)))));
    47   Context.theory_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps)))));
    48 
    48 
    49 val lookup_size = Symtab.lookup o Data.get o Context.Proof;
    49 val size_of = Symtab.lookup o Data.get o Context.Proof;
    50 val lookup_size_global = Symtab.lookup o Data.get o Context.Theory;
    50 val size_of_global = Symtab.lookup o Data.get o Context.Theory;
    51 
    51 
    52 val zero_nat = @{const zero_class.zero (nat)};
    52 val zero_nat = @{const zero_class.zero (nat)};
    53 
    53 
    54 fun mk_plus_nat (t1, t2) = Const (@{const_name Groups.plus},
    54 fun mk_plus_nat (t1, t2) = Const (@{const_name Groups.plus},
    55   HOLogic.natT --> HOLogic.natT --> HOLogic.natT) $ t1 $ t2;
    55   HOLogic.natT --> HOLogic.natT --> HOLogic.natT) $ t1 $ t2;
    82   unfold_thms_tac ctxt [size_def] THEN
    82   unfold_thms_tac ctxt [size_def] THEN
    83   HEADGOAL (rtac (rec_o_map RS trans) THEN'
    83   HEADGOAL (rtac (rec_o_map RS trans) THEN'
    84     asm_simp_tac (ss_only (inj_maps @ size_maps @ size_o_map_simp_thms) ctxt)) THEN
    84     asm_simp_tac (ss_only (inj_maps @ size_maps @ size_o_map_simp_thms) ctxt)) THEN
    85   IF_UNSOLVED (unfold_thms_tac ctxt @{thms o_def} THEN HEADGOAL (rtac refl));
    85   IF_UNSOLVED (unfold_thms_tac ctxt @{thms o_def} THEN HEADGOAL (rtac refl));
    86 
    86 
    87 fun generate_lfp_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs),
    87 fun generate_datatype_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs), fp = Least_FP,
    88     fp_res = {bnfs = fp_bnfs, xtor_co_rec_o_map_thms = ctor_rec_o_maps, ...}, fp_nesting_bnfs,
    88       fp_res = {bnfs = fp_bnfs, xtor_co_rec_o_map_thms = ctor_rec_o_maps, ...}, fp_nesting_bnfs,
    89     live_nesting_bnfs, ...} : fp_sugar) :: _) lthy0 =
    89       live_nesting_bnfs, ...} : fp_sugar) :: _) lthy0 =
    90   let
    90     let
    91     val data = Data.get (Context.Proof lthy0);
    91       val data = Data.get (Context.Proof lthy0);
    92 
    92 
    93     val Ts = map #T fp_sugars
    93       val Ts = map #T fp_sugars
    94     val T_names = map (fst o dest_Type) Ts;
    94       val T_names = map (fst o dest_Type) Ts;
    95     val nn = length Ts;
    95       val nn = length Ts;
    96 
    96 
    97     val B_ify = Term.typ_subst_atomic (As ~~ Bs);
    97       val B_ify = Term.typ_subst_atomic (As ~~ Bs);
    98 
    98 
    99     val recs = map #co_rec fp_sugars;
    99       val recs = map #co_rec fp_sugars;
   100     val rec_thmss = map #co_rec_thms fp_sugars;
   100       val rec_thmss = map #co_rec_thms fp_sugars;
   101     val rec_Ts as rec_T1 :: _ = map fastype_of recs;
   101       val rec_Ts as rec_T1 :: _ = map fastype_of recs;
   102     val rec_arg_Ts = binder_fun_types rec_T1;
   102       val rec_arg_Ts = binder_fun_types rec_T1;
   103     val Cs = map body_type rec_Ts;
   103       val Cs = map body_type rec_Ts;
   104     val Cs_rho = map (rpair HOLogic.natT) Cs;
   104       val Cs_rho = map (rpair HOLogic.natT) Cs;
   105     val substCnatT = Term.subst_atomic_types Cs_rho;
   105       val substCnatT = Term.subst_atomic_types Cs_rho;
   106 
   106 
   107     val f_Ts = map mk_to_natT As;
   107       val f_Ts = map mk_to_natT As;
   108     val f_TsB = map mk_to_natT Bs;
   108       val f_TsB = map mk_to_natT Bs;
   109     val num_As = length As;
   109       val num_As = length As;
   110 
   110 
   111     fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0);
   111       fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0);
   112 
   112 
   113     val f_names = variant_names num_As "f";
   113       val f_names = variant_names num_As "f";
   114     val fs = map2 (curry Free) f_names f_Ts;
   114       val fs = map2 (curry Free) f_names f_Ts;
   115     val fsB = map2 (curry Free) f_names f_TsB;
   115       val fsB = map2 (curry Free) f_names f_TsB;
   116     val As_fs = As ~~ fs;
   116       val As_fs = As ~~ fs;
   117 
   117 
   118     val size_bs =
   118       val size_bs =
   119       map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o
   119         map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o
   120         Long_Name.base_name) T_names;
   120           Long_Name.base_name) T_names;
   121 
   121 
   122     fun is_pair_C @{type_name prod} [_, T'] = member (op =) Cs T'
   122       fun is_pair_C @{type_name prod} [_, T'] = member (op =) Cs T'
   123       | is_pair_C _ _ = false;
   123         | is_pair_C _ _ = false;
   124 
   124 
   125     fun mk_size_of_typ (T as TFree _) =
   125       fun mk_size_of_typ (T as TFree _) =
   126         pair (case AList.lookup (op =) As_fs T of
   126           pair (case AList.lookup (op =) As_fs T of
   127             SOME f => f
   127               SOME f => f
   128           | NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T)
   128             | NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T)
   129       | mk_size_of_typ (T as Type (s, Ts)) =
   129         | mk_size_of_typ (T as Type (s, Ts)) =
   130         if is_pair_C s Ts then
   130           if is_pair_C s Ts then
   131           pair (snd_const T)
   131             pair (snd_const T)
   132         else if exists (exists_subtype_in (As @ Cs)) Ts then
   132           else if exists (exists_subtype_in (As @ Cs)) Ts then
   133           (case Symtab.lookup data s of
   133             (case Symtab.lookup data s of
   134             SOME (size_name, (_, size_o_maps)) =>
   134               SOME (size_name, (_, size_o_maps)) =>
   135             let
   135               let
   136               val (args, size_o_mapss') = split_list (map (fn T => mk_size_of_typ T []) Ts);
   136                 val (args, size_o_mapss') = split_list (map (fn T => mk_size_of_typ T []) Ts);
   137               val size_const = Const (size_name, map fastype_of args ---> mk_to_natT T);
   137                 val size_const = Const (size_name, map fastype_of args ---> mk_to_natT T);
   138             in
   138               in
   139               fold (union Thm.eq_thm_prop) (size_o_maps :: size_o_mapss')
   139                 fold (union Thm.eq_thm_prop) (size_o_maps :: size_o_mapss')
   140               #> pair (Term.list_comb (size_const, args))
   140                 #> pair (Term.list_comb (size_const, args))
   141             end
   141               end
   142           | _ => pair (mk_abs_zero_nat T))
   142             | _ => pair (mk_abs_zero_nat T))
       
   143           else
       
   144             pair (mk_abs_zero_nat T);
       
   145 
       
   146       fun mk_size_of_arg t =
       
   147         mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t)));
       
   148 
       
   149       fun mk_size_arg rec_arg_T size_o_maps =
       
   150         let
       
   151           val x_Ts = binder_types rec_arg_T;
       
   152           val m = length x_Ts;
       
   153           val x_names = variant_names m "x";
       
   154           val xs = map2 (curry Free) x_names x_Ts;
       
   155           val (summands, size_o_maps') =
       
   156             fold_map mk_size_of_arg xs size_o_maps
       
   157             |>> remove (op =) zero_nat;
       
   158           val sum =
       
   159             if null summands then HOLogic.zero
       
   160             else foldl1 mk_plus_nat (summands @ [HOLogic.Suc_zero]);
       
   161         in
       
   162           (fold_rev Term.lambda (map substCnatT xs) sum, size_o_maps')
       
   163         end;
       
   164 
       
   165       fun mk_size_rhs recx size_o_maps =
       
   166         fold_map mk_size_arg rec_arg_Ts size_o_maps
       
   167         |>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args)));
       
   168 
       
   169       val maybe_conceal_def_binding = Thm.def_binding
       
   170         #> Config.get lthy0 bnf_note_all = false ? Binding.conceal;
       
   171 
       
   172       val (size_rhss, nested_size_o_maps) = fold_map mk_size_rhs recs [];
       
   173       val size_Ts = map fastype_of size_rhss;
       
   174 
       
   175       val ((raw_size_consts, raw_size_defs), (lthy1', lthy1)) = lthy0
       
   176         |> apfst split_list o fold_map2 (fn b => fn rhs =>
       
   177             Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs))
       
   178             #>> apsnd snd)
       
   179           size_bs size_rhss
       
   180         ||> `Local_Theory.restore;
       
   181 
       
   182       val phi = Proof_Context.export_morphism lthy1 lthy1';
       
   183 
       
   184       val size_defs = map (Morphism.thm phi) raw_size_defs;
       
   185 
       
   186       val size_consts0 = map (Morphism.term phi) raw_size_consts;
       
   187       val size_consts = map2 retype_const_or_free size_Ts size_consts0;
       
   188       val size_constsB = map (Term.map_types B_ify) size_consts;
       
   189 
       
   190       val zeros = map mk_abs_zero_nat As;
       
   191 
       
   192       val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts;
       
   193       val overloaded_size_Ts = map fastype_of overloaded_size_rhss;
       
   194       val overloaded_size_consts = map (curry Const @{const_name size}) overloaded_size_Ts;
       
   195       val overloaded_size_def_bs =
       
   196         map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs;
       
   197 
       
   198       fun define_overloaded_size def_b lhs0 rhs lthy =
       
   199         let
       
   200           val Free (c, _) = Syntax.check_term lthy lhs0;
       
   201           val (thm, lthy') = lthy
       
   202             |> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs))
       
   203             |-> (fn (t, (_, thm)) => Spec_Rules.add Spec_Rules.Equational ([t], [thm]) #> pair thm);
       
   204           val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy');
       
   205           val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm;
       
   206         in (thm', lthy') end;
       
   207 
       
   208       val (overloaded_size_defs, lthy2) = lthy1
       
   209         |> Local_Theory.background_theory_result
       
   210           (Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size])
       
   211            #> fold_map3 define_overloaded_size overloaded_size_def_bs overloaded_size_consts
       
   212              overloaded_size_rhss
       
   213            ##> Class.prove_instantiation_instance (K (Class.intro_classes_tac []))
       
   214            ##> Local_Theory.exit_global);
       
   215 
       
   216       val size_defs' =
       
   217         map (mk_unabs_def (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs;
       
   218       val size_defs_unused_0 =
       
   219         map (mk_unabs_def_unused_0 (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs;
       
   220       val overloaded_size_defs' =
       
   221         map (mk_unabs_def 1 o (fn thm => thm RS meta_eq_to_obj_eq)) overloaded_size_defs;
       
   222 
       
   223       val all_overloaded_size_defs = overloaded_size_defs @
       
   224         (Spec_Rules.retrieve lthy0 @{const size ('a)}
       
   225          |> map_filter (try (fn (Spec_Rules.Equational, (_, [thm])) => thm)));
       
   226 
       
   227       val nested_size_maps = map (pointfill lthy2) nested_size_o_maps @ nested_size_o_maps;
       
   228       val all_inj_maps = map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs)
       
   229         |> distinct Thm.eq_thm_prop;
       
   230 
       
   231       fun derive_size_simp size_def' simp0 =
       
   232         (trans OF [size_def', simp0])
       
   233         |> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def
       
   234           snd_conv} @ all_inj_maps @ nested_size_maps) lthy2)
       
   235         |> fold_thms lthy2 size_defs_unused_0;
       
   236 
       
   237       fun derive_overloaded_size_simp overloaded_size_def' simp0 =
       
   238         (trans OF [overloaded_size_def', simp0])
       
   239         |> unfold_thms lthy2 @{thms add_0_left add_0_right}
       
   240         |> fold_thms lthy2 all_overloaded_size_defs;
       
   241 
       
   242       val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss;
       
   243       val size_simps = flat size_simpss;
       
   244       val overloaded_size_simpss =
       
   245         map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss;
       
   246       val size_thmss = map2 append size_simpss overloaded_size_simpss;
       
   247 
       
   248       val ABs = As ~~ Bs;
       
   249       val g_names = variant_names num_As "g";
       
   250       val gs = map2 (curry Free) g_names (map (op -->) ABs);
       
   251 
       
   252       val liveness = map (op <>) ABs;
       
   253       val live_gs = AList.find (op =) (gs ~~ liveness) true;
       
   254       val live = length live_gs;
       
   255 
       
   256       val maps0 = map map_of_bnf fp_bnfs;
       
   257 
       
   258       val (rec_o_map_thmss, size_o_map_thmss) =
       
   259         if live = 0 then
       
   260           `I (replicate nn [])
   143         else
   261         else
   144           pair (mk_abs_zero_nat T);
   262           let
   145 
   263             val pre_bnfs = map #pre_bnf fp_sugars;
   146     fun mk_size_of_arg t =
   264             val pre_map_defs = map map_def_of_bnf pre_bnfs;
   147       mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t)));
   265             val live_nesting_map_ident0s = map map_ident0_of_bnf live_nesting_bnfs;
   148 
   266             val abs_inverses = map (#abs_inverse o #absT_info) fp_sugars;
   149     fun mk_size_arg rec_arg_T size_o_maps =
   267             val rec_defs = map #co_rec_def fp_sugars;
   150       let
   268 
   151         val x_Ts = binder_types rec_arg_T;
   269             val gmaps = map (fn map0 => Term.list_comb (mk_map live As Bs map0, live_gs)) maps0;
   152         val m = length x_Ts;
   270 
   153         val x_names = variant_names m "x";
   271             val num_rec_args = length rec_arg_Ts;
   154         val xs = map2 (curry Free) x_names x_Ts;
   272             val h_Ts = map B_ify rec_arg_Ts;
   155         val (summands, size_o_maps') =
   273             val h_names = variant_names num_rec_args "h";
   156           fold_map mk_size_of_arg xs size_o_maps
   274             val hs = map2 (curry Free) h_names h_Ts;
   157           |>> remove (op =) zero_nat;
   275             val hrecs = map (fn recx => Term.list_comb (Term.map_types B_ify recx, hs)) recs;
   158         val sum =
   276 
   159           if null summands then HOLogic.zero
   277             val rec_o_map_lhss = map2 (curry HOLogic.mk_comp) hrecs gmaps;
   160           else foldl1 mk_plus_nat (summands @ [HOLogic.Suc_zero]);
   278 
   161       in
   279             val ABgs = ABs ~~ gs;
   162         (fold_rev Term.lambda (map substCnatT xs) sum, size_o_maps')
   280 
   163       end;
   281             fun mk_rec_arg_arg (x as Free (_, T)) =
   164 
   282               let val U = B_ify T in
   165     fun mk_size_rhs recx size_o_maps =
   283                 if T = U then x else build_map lthy2 [] (the o AList.lookup (op =) ABgs) (T, U) $ x
   166       fold_map mk_size_arg rec_arg_Ts size_o_maps
   284               end;
   167       |>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args)));
   285 
   168 
   286             fun mk_rec_o_map_arg rec_arg_T h =
   169     val maybe_conceal_def_binding = Thm.def_binding
   287               let
   170       #> Config.get lthy0 bnf_note_all = false ? Binding.conceal;
   288                 val x_Ts = binder_types rec_arg_T;
   171 
   289                 val m = length x_Ts;
   172     val (size_rhss, nested_size_o_maps) = fold_map mk_size_rhs recs [];
   290                 val x_names = variant_names m "x";
   173     val size_Ts = map fastype_of size_rhss;
   291                 val xs = map2 (curry Free) x_names x_Ts;
   174 
   292                 val xs' = map mk_rec_arg_arg xs;
   175     val ((raw_size_consts, raw_size_defs), (lthy1', lthy1)) = lthy0
   293               in
   176       |> apfst split_list o fold_map2 (fn b => fn rhs =>
   294                 fold_rev Term.lambda xs (Term.list_comb (h, xs'))
   177           Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs)) #>> apsnd snd)
   295               end;
   178         size_bs size_rhss
   296 
   179       ||> `Local_Theory.restore;
   297             fun mk_rec_o_map_rhs recx =
   180 
   298               let val args = map2 mk_rec_o_map_arg rec_arg_Ts hs in
   181     val phi = Proof_Context.export_morphism lthy1 lthy1';
   299                 Term.list_comb (recx, args)
   182 
   300               end;
   183     val size_defs = map (Morphism.thm phi) raw_size_defs;
   301 
   184 
   302             val rec_o_map_rhss = map mk_rec_o_map_rhs recs;
   185     val size_consts0 = map (Morphism.term phi) raw_size_consts;
   303 
   186     val size_consts = map2 retype_const_or_free size_Ts size_consts0;
   304             val rec_o_map_goals =
   187     val size_constsB = map (Term.map_types B_ify) size_consts;
   305               map2 (fold_rev (fold_rev Logic.all) [gs, hs] o HOLogic.mk_Trueprop oo
   188 
   306                 curry HOLogic.mk_eq) rec_o_map_lhss rec_o_map_rhss;
   189     val zeros = map mk_abs_zero_nat As;
   307             val rec_o_map_thms =
   190 
   308               map3 (fn goal => fn rec_def => fn ctor_rec_o_map =>
   191     val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts;
   309                   Goal.prove_sorry lthy2 [] [] goal (fn {context = ctxt, ...} =>
   192     val overloaded_size_Ts = map fastype_of overloaded_size_rhss;
   310                     mk_rec_o_map_tac ctxt rec_def pre_map_defs live_nesting_map_ident0s abs_inverses
   193     val overloaded_size_consts = map (curry Const @{const_name size}) overloaded_size_Ts;
   311                       ctor_rec_o_map)
   194     val overloaded_size_def_bs =
   312                   |> Thm.close_derivation)
   195       map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs;
   313                 rec_o_map_goals rec_defs ctor_rec_o_maps;
   196 
   314 
   197     fun define_overloaded_size def_b lhs0 rhs lthy =
   315             val size_o_map_conds =
   198       let
   316               if exists (can Logic.dest_implies o Thm.prop_of) nested_size_o_maps then
   199         val Free (c, _) = Syntax.check_term lthy lhs0;
   317                 map (HOLogic.mk_Trueprop o mk_inj) live_gs
   200         val (thm, lthy') = lthy
   318               else
   201           |> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs))
   319                 [];
   202           |-> (fn (t, (_, thm)) => Spec_Rules.add Spec_Rules.Equational ([t], [thm]) #> pair thm);
   320 
   203         val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy');
   321             val fsizes = map (fn size_constB => Term.list_comb (size_constB, fsB)) size_constsB;
   204         val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm;
   322             val size_o_map_lhss = map2 (curry HOLogic.mk_comp) fsizes gmaps;
   205       in (thm', lthy') end;
   323 
   206 
   324             val fgs = map2 (fn fB => fn g as Free (_, Type (_, [A, B])) =>
   207     val (overloaded_size_defs, lthy2) = lthy1
   325               if A = B then fB else HOLogic.mk_comp (fB, g)) fsB gs;
   208       |> Local_Theory.background_theory_result
   326             val size_o_map_rhss = map (fn c => Term.list_comb (c, fgs)) size_consts;
   209         (Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size])
   327 
   210          #> fold_map3 define_overloaded_size overloaded_size_def_bs overloaded_size_consts
   328             val size_o_map_goals =
   211            overloaded_size_rhss
   329               map2 (fold_rev (fold_rev Logic.all) [fsB, gs] o
   212          ##> Class.prove_instantiation_instance (K (Class.intro_classes_tac []))
   330                 curry Logic.list_implies size_o_map_conds o HOLogic.mk_Trueprop oo
   213          ##> Local_Theory.exit_global);
   331                 curry HOLogic.mk_eq) size_o_map_lhss size_o_map_rhss;
   214 
   332 
   215     val size_defs' =
   333             (* The "size o map" theorem generation will fail if "nested_size_maps" is incomplete,
   216       map (mk_unabs_def (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs;
   334                which occurs when there is recursion through non-datatypes. In this case, we simply
   217     val size_defs_unused_0 =
   335                avoid generating the theorem. The resulting characteristic lemmas are then expressed
   218       map (mk_unabs_def_unused_0 (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs;
   336                in terms of "map", which is not the end of the world. *)
   219     val overloaded_size_defs' =
   337             val size_o_map_thmss =
   220       map (mk_unabs_def 1 o (fn thm => thm RS meta_eq_to_obj_eq)) overloaded_size_defs;
   338               map3 (fn goal => fn size_def => the_list o try (fn rec_o_map =>
   221 
   339                   Goal.prove (*no sorry*) lthy2 [] [] goal (fn {context = ctxt, ...} =>
   222     val all_overloaded_size_defs = overloaded_size_defs @
   340                     mk_size_o_map_tac ctxt size_def rec_o_map all_inj_maps nested_size_maps)
   223       (Spec_Rules.retrieve lthy0 @{const size ('a)}
   341                   |> Thm.close_derivation))
   224        |> map_filter (try (fn (Spec_Rules.Equational, (_, [thm])) => thm)));
   342                 size_o_map_goals size_defs rec_o_map_thms
   225 
   343           in
   226     val nested_size_maps = map (pointfill lthy2) nested_size_o_maps @ nested_size_o_maps;
   344             (map single rec_o_map_thms, size_o_map_thmss)
   227     val all_inj_maps = map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs)
   345           end;
   228       |> distinct Thm.eq_thm_prop;
   346 
   229 
   347       val massage_multi_notes =
   230     fun derive_size_simp size_def' simp0 =
   348         maps (fn (thmN, thmss, attrs) =>
   231       (trans OF [size_def', simp0])
   349           map2 (fn T_name => fn thms =>
   232       |> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def snd_conv} @
   350               ((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs),
   233         all_inj_maps @ nested_size_maps) lthy2)
   351                [(thms, [])]))
   234       |> fold_thms lthy2 size_defs_unused_0;
   352             T_names thmss)
   235 
   353         #> filter_out (null o fst o hd o snd);
   236     fun derive_overloaded_size_simp overloaded_size_def' simp0 =
   354 
   237       (trans OF [overloaded_size_def', simp0])
   355       val notes =
   238       |> unfold_thms lthy2 @{thms add_0_left add_0_right}
   356         [(rec_o_mapN, rec_o_map_thmss, []),
   239       |> fold_thms lthy2 all_overloaded_size_defs;
   357          (sizeN, size_thmss, code_nitpicksimp_simp_attrs),
   240 
   358          (size_o_mapN, size_o_map_thmss, [])]
   241     val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss;
   359         |> massage_multi_notes;
   242     val size_simps = flat size_simpss;
   360 
   243     val overloaded_size_simpss =
   361       val (noted, lthy3) =
   244       map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss;
   362         lthy2
   245     val size_thmss = map2 append size_simpss overloaded_size_simpss;
   363         |> Spec_Rules.add Spec_Rules.Equational (size_consts, size_simps)
   246 
   364         |> Local_Theory.notes notes;
   247     val ABs = As ~~ Bs;
   365 
   248     val g_names = variant_names num_As "g";
   366       val phi0 = substitute_noted_thm noted;
   249     val gs = map2 (curry Free) g_names (map (op -->) ABs);
   367     in
   250 
   368       lthy3
   251     val liveness = map (op <>) ABs;
   369       |> Local_Theory.declaration {syntax = false, pervasive = true}
   252     val live_gs = AList.find (op =) (gs ~~ liveness) true;
   370         (fn phi => Data.map (fold2 (fn T_name => fn Const (size_name, _) =>
   253     val live = length live_gs;
   371              Symtab.update (T_name, (size_name,
   254 
   372                pairself (map (Morphism.thm (phi0 $> phi))) (size_simps, flat size_o_map_thmss))))
   255     val maps0 = map map_of_bnf fp_bnfs;
   373            T_names size_consts))
   256 
   374     end
   257     val (rec_o_map_thmss, size_o_map_thmss) =
   375   | generate_datatype_size _ lthy = lthy;
   258       if live = 0 then
   376 
   259         `I (replicate nn [])
   377 val _ = Theory.setup (fp_sugar_interpretation (map_local_theory o generate_datatype_size)
   260       else
   378   generate_datatype_size);
   261         let
       
   262           val pre_bnfs = map #pre_bnf fp_sugars;
       
   263           val pre_map_defs = map map_def_of_bnf pre_bnfs;
       
   264           val live_nesting_map_ident0s = map map_ident0_of_bnf live_nesting_bnfs;
       
   265           val abs_inverses = map (#abs_inverse o #absT_info) fp_sugars;
       
   266           val rec_defs = map #co_rec_def fp_sugars;
       
   267 
       
   268           val gmaps = map (fn map0 => Term.list_comb (mk_map live As Bs map0, live_gs)) maps0;
       
   269 
       
   270           val num_rec_args = length rec_arg_Ts;
       
   271           val h_Ts = map B_ify rec_arg_Ts;
       
   272           val h_names = variant_names num_rec_args "h";
       
   273           val hs = map2 (curry Free) h_names h_Ts;
       
   274           val hrecs = map (fn recx => Term.list_comb (Term.map_types B_ify recx, hs)) recs;
       
   275 
       
   276           val rec_o_map_lhss = map2 (curry HOLogic.mk_comp) hrecs gmaps;
       
   277 
       
   278           val ABgs = ABs ~~ gs;
       
   279 
       
   280           fun mk_rec_arg_arg (x as Free (_, T)) =
       
   281             let val U = B_ify T in
       
   282               if T = U then x else build_map lthy2 [] (the o AList.lookup (op =) ABgs) (T, U) $ x
       
   283             end;
       
   284 
       
   285           fun mk_rec_o_map_arg rec_arg_T h =
       
   286             let
       
   287               val x_Ts = binder_types rec_arg_T;
       
   288               val m = length x_Ts;
       
   289               val x_names = variant_names m "x";
       
   290               val xs = map2 (curry Free) x_names x_Ts;
       
   291               val xs' = map mk_rec_arg_arg xs;
       
   292             in
       
   293               fold_rev Term.lambda xs (Term.list_comb (h, xs'))
       
   294             end;
       
   295 
       
   296           fun mk_rec_o_map_rhs recx =
       
   297             let val args = map2 mk_rec_o_map_arg rec_arg_Ts hs in
       
   298               Term.list_comb (recx, args)
       
   299             end;
       
   300 
       
   301           val rec_o_map_rhss = map mk_rec_o_map_rhs recs;
       
   302 
       
   303           val rec_o_map_goals =
       
   304             map2 (fold_rev (fold_rev Logic.all) [gs, hs] o HOLogic.mk_Trueprop oo
       
   305               curry HOLogic.mk_eq) rec_o_map_lhss rec_o_map_rhss;
       
   306           val rec_o_map_thms =
       
   307             map3 (fn goal => fn rec_def => fn ctor_rec_o_map =>
       
   308                 Goal.prove_sorry lthy2 [] [] goal (fn {context = ctxt, ...} =>
       
   309                   mk_rec_o_map_tac ctxt rec_def pre_map_defs live_nesting_map_ident0s abs_inverses
       
   310                     ctor_rec_o_map)
       
   311                 |> Thm.close_derivation)
       
   312               rec_o_map_goals rec_defs ctor_rec_o_maps;
       
   313 
       
   314           val size_o_map_conds =
       
   315             if exists (can Logic.dest_implies o Thm.prop_of) nested_size_o_maps then
       
   316               map (HOLogic.mk_Trueprop o mk_inj) live_gs
       
   317             else
       
   318               [];
       
   319 
       
   320           val fsizes = map (fn size_constB => Term.list_comb (size_constB, fsB)) size_constsB;
       
   321           val size_o_map_lhss = map2 (curry HOLogic.mk_comp) fsizes gmaps;
       
   322 
       
   323           val fgs = map2 (fn fB => fn g as Free (_, Type (_, [A, B])) =>
       
   324             if A = B then fB else HOLogic.mk_comp (fB, g)) fsB gs;
       
   325           val size_o_map_rhss = map (fn c => Term.list_comb (c, fgs)) size_consts;
       
   326 
       
   327           val size_o_map_goals =
       
   328             map2 (fold_rev (fold_rev Logic.all) [fsB, gs] o
       
   329               curry Logic.list_implies size_o_map_conds o HOLogic.mk_Trueprop oo
       
   330               curry HOLogic.mk_eq) size_o_map_lhss size_o_map_rhss;
       
   331 
       
   332           (* The "size o map" theorem generation will fail if 'nested_size_maps' is incomplete,
       
   333              which occurs when there is recursion through non-datatypes. In this case, we simply
       
   334              avoid generating the theorem. The resulting characteristic lemmas are then expressed
       
   335              in terms of "map", which is not the end of the world. *)
       
   336           val size_o_map_thmss =
       
   337             map3 (fn goal => fn size_def => the_list o try (fn rec_o_map =>
       
   338                 Goal.prove (*no sorry*) lthy2 [] [] goal (fn {context = ctxt, ...} =>
       
   339                   mk_size_o_map_tac ctxt size_def rec_o_map all_inj_maps nested_size_maps)
       
   340                 |> Thm.close_derivation))
       
   341               size_o_map_goals size_defs rec_o_map_thms
       
   342         in
       
   343           (map single rec_o_map_thms, size_o_map_thmss)
       
   344         end;
       
   345 
       
   346     val massage_multi_notes =
       
   347       maps (fn (thmN, thmss, attrs) =>
       
   348         map2 (fn T_name => fn thms =>
       
   349             ((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs),
       
   350              [(thms, [])]))
       
   351           T_names thmss)
       
   352       #> filter_out (null o fst o hd o snd);
       
   353 
       
   354     val notes =
       
   355       [(rec_o_mapN, rec_o_map_thmss, []),
       
   356        (sizeN, size_thmss, code_nitpicksimp_simp_attrs),
       
   357        (size_o_mapN, size_o_map_thmss, [])]
       
   358       |> massage_multi_notes;
       
   359 
       
   360     val (noted, lthy3) =
       
   361       lthy2
       
   362       |> Spec_Rules.add Spec_Rules.Equational (size_consts, size_simps)
       
   363       |> Local_Theory.notes notes;
       
   364 
       
   365     val phi0 = substitute_noted_thm noted;
       
   366   in
       
   367     lthy3
       
   368     |> Local_Theory.declaration {syntax = false, pervasive = true}
       
   369       (fn phi => Data.map (fold2 (fn T_name => fn Const (size_name, _) =>
       
   370            Symtab.update (T_name, (size_name,
       
   371              pairself (map (Morphism.thm (phi0 $> phi))) (size_simps, flat size_o_map_thmss))))
       
   372          T_names size_consts))
       
   373   end;
       
   374 
   379 
   375 end;
   380 end;