extended 'datatype_compat' to generate the expected, old-style recursor in the presence of recursion through functions
authorblanchet
Mon, 08 Sep 2014 14:03:01 +0200
changeset 58211 c1f3fa32d322
parent 58210 a456b2c03491
child 58212 f02b4f41bfd6
extended 'datatype_compat' to generate the expected, old-style recursor in the presence of recursion through functions
src/HOL/BNF_Least_Fixpoint.thy
src/HOL/Tools/BNF/bnf_fp_def_sugar.ML
src/HOL/Tools/BNF/bnf_fp_n2m_sugar.ML
src/HOL/Tools/BNF/bnf_fp_rec_sugar_util.ML
src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML
src/HOL/Tools/BNF/bnf_lfp_compat.ML
src/HOL/Tools/BNF/bnf_lfp_rec_sugar.ML
src/HOL/Tools/Old_Datatype/old_datatype_aux.ML
--- a/src/HOL/BNF_Least_Fixpoint.thy	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/BNF_Least_Fixpoint.thy	Mon Sep 08 14:03:01 2014 +0200
@@ -181,6 +181,50 @@
 lemma ssubst_Pair_rhs: "\<lbrakk>(r, s) \<in> R; s' = s\<rbrakk> \<Longrightarrow> (r, s') \<in> R"
   by (rule ssubst)
 
+lemma all_mem_range1:
+  "(\<And>y. y \<in> range f \<Longrightarrow> P y) \<equiv> (\<And>x. P (f x)) "
+  by (rule equal_intr_rule) fast+
+
+lemma all_mem_range2:
+  "(\<And>fa y. fa \<in> range f \<Longrightarrow> y \<in> range fa \<Longrightarrow> P y) \<equiv> (\<And>x xa. P (f x xa))"
+  by (rule equal_intr_rule) fast+
+
+lemma all_mem_range3:
+  "(\<And>fa fb y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> y \<in> range fb \<Longrightarrow> P y) \<equiv> (\<And>x xa xb. P (f x xa xb))"
+  by (rule equal_intr_rule) fast+
+
+lemma all_mem_range4:
+  "(\<And>fa fb fc y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> fc \<in> range fb \<Longrightarrow> y \<in> range fc \<Longrightarrow> P y) \<equiv>
+   (\<And>x xa xb xc. P (f x xa xb xc))"
+  by (rule equal_intr_rule) fast+
+
+lemma all_mem_range5:
+  "(\<And>fa fb fc fd y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> fc \<in> range fb \<Longrightarrow> fd \<in> range fc \<Longrightarrow>
+     y \<in> range fd \<Longrightarrow> P y) \<equiv>
+   (\<And>x xa xb xc xd. P (f x xa xb xc xd))"
+  by (rule equal_intr_rule) fast+
+
+lemma all_mem_range6:
+  "(\<And>fa fb fc fd fe ff y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> fc \<in> range fb \<Longrightarrow> fd \<in> range fc \<Longrightarrow>
+     fe \<in> range fd \<Longrightarrow> ff \<in> range fe \<Longrightarrow> y \<in> range ff \<Longrightarrow> P y) \<equiv>
+   (\<And>x xa xb xc xd xe xf. P (f x xa xb xc xd xe xf))"
+  by (rule equal_intr_rule) (fastforce, fast)
+
+lemma all_mem_range7:
+  "(\<And>fa fb fc fd fe ff fg y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> fc \<in> range fb \<Longrightarrow> fd \<in> range fc \<Longrightarrow>
+     fe \<in> range fd \<Longrightarrow> ff \<in> range fe \<Longrightarrow> fg \<in> range ff \<Longrightarrow> y \<in> range fg \<Longrightarrow> P y) \<equiv>
+   (\<And>x xa xb xc xd xe xf xg. P (f x xa xb xc xd xe xf xg))"
+  by (rule equal_intr_rule) (fastforce, fast)
+
+lemma all_mem_range8:
+  "(\<And>fa fb fc fd fe ff fg fh y. fa \<in> range f \<Longrightarrow> fb \<in> range fa \<Longrightarrow> fc \<in> range fb \<Longrightarrow> fd \<in> range fc \<Longrightarrow>
+     fe \<in> range fd \<Longrightarrow> ff \<in> range fe \<Longrightarrow> fg \<in> range ff \<Longrightarrow> fh \<in> range fg \<Longrightarrow> y \<in> range fh \<Longrightarrow> P y) \<equiv>
+   (\<And>x xa xb xc xd xe xf xg xh. P (f x xa xb xc xd xe xf xg xh))"
+  by (rule equal_intr_rule) (fastforce, fast)
+
+lemmas all_mem_range = all_mem_range1 all_mem_range2 all_mem_range3 all_mem_range4 all_mem_range5
+  all_mem_range6 all_mem_range7 all_mem_range8
+
 ML_file "Tools/BNF/bnf_lfp_util.ML"
 ML_file "Tools/BNF/bnf_lfp_tactics.ML"
 ML_file "Tools/BNF/bnf_lfp.ML"
--- a/src/HOL/Tools/BNF/bnf_fp_def_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_fp_def_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -536,7 +536,7 @@
 
     val phi = Proof_Context.export_morphism lthy lthy';
 
-    val cst' = mk_co_rec thy fp fpT Cs (Morphism.term phi cst);
+    val cst' = mk_co_rec thy fp Cs fpT (Morphism.term phi cst);
     val def' = Morphism.thm phi def;
   in
     ((cst', def'), lthy')
@@ -1464,7 +1464,7 @@
               sel_default_eqs) lthy
           end;
 
-        fun derive_maps_sets_rels (ctr_sugar as {casex, case_cong, case_thms, discs, selss, ctrs,
+        fun derive_map_set_rel_thms (ctr_sugar as {casex, case_cong, case_thms, discs, selss, ctrs,
             exhaust, exhaust_discs, disc_thmss, sel_thmss, injects, distincts, distinct_discsss,
             ...} : ctr_sugar, lthy) =
           if live = 0 then
@@ -1989,7 +1989,7 @@
           (((maps_sets_rels, (ctrs, xss, ctr_defs, ctr_sugar)), co_rec_res), lthy);
       in
         (wrap_ctrs
-         #> derive_maps_sets_rels
+         #> derive_map_set_rel_thms
          ##>>
            (if fp = Least_FP then define_rec (the recs_args_types) mk_binding fpTs Cs reps
            else define_corec (the corecs_args_types) mk_binding fpTs Cs abss) xtor_co_rec
--- a/src/HOL/Tools/BNF/bnf_fp_n2m_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_fp_n2m_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -227,58 +227,56 @@
 
         val fp_absT_infos = map #absT_info fp_sugars0;
 
-          val ((pre_bnfs, absT_infos), (fp_res as {xtor_co_recs = xtor_co_recs0, xtor_co_induct,
-                 dtor_injects, dtor_ctors, xtor_co_rec_thms, ...}, lthy)) =
-            fp_bnf (construct_mutualized_fp fp cliques fpTs fp_sugars0) fp_bs As' killed_As' fp_eqs
-              no_defs_lthy0;
+        val ((pre_bnfs, absT_infos), (fp_res as {xtor_co_recs = xtor_co_recs0, xtor_co_induct,
+               dtor_injects, dtor_ctors, xtor_co_rec_thms, ...}, lthy)) =
+          fp_bnf (construct_mutualized_fp fp cliques fpTs fp_sugars0) fp_bs As' killed_As' fp_eqs
+            no_defs_lthy0;
 
-          val fp_abs_inverses = map #abs_inverse fp_absT_infos;
-          val fp_type_definitions = map #type_definition fp_absT_infos;
+        val fp_abs_inverses = map #abs_inverse fp_absT_infos;
+        val fp_type_definitions = map #type_definition fp_absT_infos;
 
-          val abss = map #abs absT_infos;
-          val reps = map #rep absT_infos;
-          val absTs = map #absT absT_infos;
-          val repTs = map #repT absT_infos;
-          val abs_inverses = map #abs_inverse absT_infos;
+        val abss = map #abs absT_infos;
+        val reps = map #rep absT_infos;
+        val absTs = map #absT absT_infos;
+        val repTs = map #repT absT_infos;
+        val abs_inverses = map #abs_inverse absT_infos;
 
-          val fp_nesting_bnfs = nesting_bnfs lthy ctrXs_Tsss Xs;
-          val live_nesting_bnfs = nesting_bnfs lthy ctrXs_Tsss As;
+        val fp_nesting_bnfs = nesting_bnfs lthy ctrXs_Tsss Xs;
+        val live_nesting_bnfs = nesting_bnfs lthy ctrXs_Tsss As;
 
-          val ((xtor_co_recs, recs_args_types, corecs_args_types), _) =
-            mk_co_recs_prelims fp ctr_Tsss fpTs Cs absTs repTs ns mss xtor_co_recs0 lthy;
+        val ((xtor_co_recs, recs_args_types, corecs_args_types), _) =
+          mk_co_recs_prelims fp ctr_Tsss fpTs Cs absTs repTs ns mss xtor_co_recs0 lthy;
 
-          fun mk_binding b suf = Binding.suffix_name ("_" ^ suf) b;
+        fun mk_binding b pre = Binding.prefix_name (pre ^ "_") b;
 
-          val ((co_recs, co_rec_defs), lthy) =
-            fold_map2 (fn b =>
-                if fp = Least_FP then
-                  define_rec (the recs_args_types) (mk_binding b) fpTs Cs reps
-                else
-                  define_corec (the corecs_args_types) (mk_binding b) fpTs Cs abss)
-              fp_bs xtor_co_recs lthy
-            |>> split_list;
+        val ((co_recs, co_rec_defs), lthy) =
+          fold_map2 (fn b =>
+              if fp = Least_FP then define_rec (the recs_args_types) (mk_binding b) fpTs Cs reps
+              else define_corec (the corecs_args_types) (mk_binding b) fpTs Cs abss)
+            fp_bs xtor_co_recs lthy
+          |>> split_list;
 
-          val ((common_co_inducts, co_inductss', co_rec_thmss, co_rec_disc_thmss,
-              co_rec_sel_thmsss), fp_sugar_thms) =
-            if fp = Least_FP then
-              derive_induct_recs_thms_for_types pre_bnfs recs_args_types xtor_co_induct
-                xtor_co_rec_thms live_nesting_bnfs fp_nesting_bnfs fpTs Cs Xs ctrXs_Tsss
-                fp_abs_inverses fp_type_definitions abs_inverses ctrss ctr_defss co_recs co_rec_defs
-                lthy
-              |> `(fn ((inducts, induct, _), (rec_thmss, _)) =>
-                ([induct], [inducts], rec_thmss, replicate nn [], replicate nn []))
-              ||> (fn info => (SOME info, NONE))
-            else
-              derive_coinduct_corecs_thms_for_types pre_bnfs (the corecs_args_types)
-                xtor_co_induct dtor_injects dtor_ctors xtor_co_rec_thms live_nesting_bnfs fpTs Cs Xs
-                ctrXs_Tsss kss mss ns fp_abs_inverses abs_inverses
-                (fn thm => thm RS @{thm vimage2p_refl}) ctr_defss ctr_sugars co_recs co_rec_defs
-                (Proof_Context.export lthy no_defs_lthy) lthy
-              |> `(fn ((coinduct_thms_pairs, _), corec_thmss, corec_disc_thmss, _,
-                       (corec_sel_thmsss, _)) =>
-                (map snd coinduct_thms_pairs, map fst coinduct_thms_pairs, corec_thmss,
-                 corec_disc_thmss, corec_sel_thmsss))
-              ||> (fn info => (NONE, SOME info));
+        val ((common_co_inducts, co_inductss', co_rec_thmss, co_rec_disc_thmss, co_rec_sel_thmsss),
+             fp_sugar_thms) =
+          if fp = Least_FP then
+            derive_induct_recs_thms_for_types pre_bnfs recs_args_types xtor_co_induct
+              xtor_co_rec_thms live_nesting_bnfs fp_nesting_bnfs fpTs Cs Xs ctrXs_Tsss
+              fp_abs_inverses fp_type_definitions abs_inverses ctrss ctr_defss co_recs co_rec_defs
+              lthy
+            |> `(fn ((inducts, induct, _), (rec_thmss, _)) =>
+              ([induct], [inducts], rec_thmss, replicate nn [], replicate nn []))
+            ||> (fn info => (SOME info, NONE))
+          else
+            derive_coinduct_corecs_thms_for_types pre_bnfs (the corecs_args_types)
+              xtor_co_induct dtor_injects dtor_ctors xtor_co_rec_thms live_nesting_bnfs fpTs Cs Xs
+              ctrXs_Tsss kss mss ns fp_abs_inverses abs_inverses
+              (fn thm => thm RS @{thm vimage2p_refl}) ctr_defss ctr_sugars co_recs co_rec_defs
+              (Proof_Context.export lthy no_defs_lthy) lthy
+            |> `(fn ((coinduct_thms_pairs, _), corec_thmss, corec_disc_thmss, _,
+                     (corec_sel_thmsss, _)) =>
+              (map snd coinduct_thms_pairs, map fst coinduct_thms_pairs, corec_thmss,
+               corec_disc_thmss, corec_sel_thmsss))
+            ||> (fn info => (NONE, SOME info));
 
         val phi = Proof_Context.export_morphism no_defs_lthy no_defs_lthy0;
 
--- a/src/HOL/Tools/BNF/bnf_fp_rec_sugar_util.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_fp_rec_sugar_util.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -37,7 +37,7 @@
   val mk_compN: int -> typ list -> term * term -> term
   val mk_comp: typ list -> term * term -> term
 
-  val mk_co_rec: theory -> fp_kind -> typ -> typ list -> term -> term
+  val mk_co_rec: theory -> fp_kind -> typ list -> typ -> term -> term
 
   val mk_conjunctN: int -> int -> thm
   val conj_dests: int -> thm -> thm list
@@ -105,7 +105,7 @@
 
 val mk_comp = mk_compN 1;
 
-fun mk_co_rec thy fp fpT Cs t =
+fun mk_co_rec thy fp Cs fpT t =
   let
     val ((f_Cs, prebody), body) = strip_type (fastype_of t) |>> split_last;
     val fpT0 = case_fp fp prebody body;
--- a/src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -462,7 +462,7 @@
     fun mk_spec ({T, ctr_sugar as {exhaust_discs, sel_defs, ...}, co_rec = corec,
         co_rec_thms = corec_thms, co_rec_discs = corec_discs,
         co_rec_selss = corec_selss, ...} : fp_sugar) p_is q_isss f_isss f_Tsss =
-      {corec = mk_co_rec thy Greatest_FP (substAT T) perm_Cs' corec, exhaust_discs = exhaust_discs,
+      {corec = mk_co_rec thy Greatest_FP perm_Cs' (substAT T) corec, exhaust_discs = exhaust_discs,
        sel_defs = sel_defs,
        fp_nesting_maps = maps (map_thms_of_typ lthy o T_of_bnf) fp_nesting_bnfs,
        fp_nesting_map_ident0s = map map_ident0_of_bnf fp_nesting_bnfs,
--- a/src/HOL/Tools/BNF/bnf_lfp_compat.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_lfp_compat.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -43,15 +43,152 @@
 
 open Ctr_Sugar
 open BNF_Util
+open BNF_Tactics
 open BNF_FP_Util
 open BNF_FP_Def_Sugar
 open BNF_FP_N2M_Sugar
 open BNF_LFP
 
-val compatN = "compat_";
+val compat_N = "compat_";
+val rec_fun_N = "rec_fun_";
 
 datatype nesting_preference = Keep_Nesting | Unfold_Nesting;
 
+fun mk_fun_rec_rhs ctxt fpTs Cs (recs as rec1 :: _) =
+  let
+    fun repair_rec_arg_args [] [] = []
+      | repair_rec_arg_args ((g_T as Type (@{type_name fun}, _)) :: g_Ts) (g :: gs) =
+        let
+          val (x_Ts, body_T) = strip_type g_T;
+        in
+          (case try HOLogic.dest_prodT body_T of
+            NONE => [g]
+          | SOME (fst_T, _) =>
+            if member (op =) fpTs fst_T then
+              let val (xs, _) = mk_Frees "x" x_Ts ctxt in
+                map (fn mk_proj => fold_rev Term.lambda xs (mk_proj (Term.list_comb (g, xs))))
+                  [HOLogic.mk_fst, HOLogic.mk_snd]
+              end
+            else
+              [g])
+          :: repair_rec_arg_args g_Ts gs
+        end
+      | repair_rec_arg_args (g_T :: g_Ts) (g :: gs) =
+        if member (op =) fpTs g_T then
+          let
+            val j = find_index (member (op =) Cs) g_Ts;
+            val h = nth gs j;
+            val g_Ts' = nth_drop j g_Ts;
+            val gs' = nth_drop j gs;
+          in
+            [g, h] :: repair_rec_arg_args g_Ts' gs'
+          end
+        else
+          [g] :: repair_rec_arg_args g_Ts gs;
+
+    fun repair_back_rec_arg f_T f' =
+      let
+        val g_Ts = Term.binder_types f_T;
+        val (gs, _) = mk_Frees "g" g_Ts ctxt;
+      in
+        fold_rev Term.lambda gs (Term.list_comb (f',
+          flat_rec_arg_args (repair_rec_arg_args g_Ts gs)))
+      end;
+
+    val f_Ts = binder_fun_types (fastype_of rec1);
+    val (fs', _) = mk_Frees "f" (replicate (length f_Ts) Term.dummyT) ctxt;
+
+    fun mk_rec' recx =
+      fold_rev Term.lambda fs' (Term.list_comb (recx, map2 repair_back_rec_arg f_Ts fs'))
+      |> Syntax.check_term ctxt;
+  in
+    map mk_rec' recs
+  end;
+
+fun define_fun_recs fpTs Cs recs lthy =
+  let
+    val b_names = Name.variant_list [] (map base_name_of_typ fpTs);
+
+    fun mk_binding b_name =
+      Binding.qualify true (compat_N ^ b_name)
+        (Binding.prefix_name rec_fun_N (Binding.name b_name));
+
+    val bs = map mk_binding b_names;
+    val rhss = mk_fun_rec_rhs lthy fpTs Cs recs;
+  in
+    fold_map3 (define_co_rec_as Least_FP Cs) fpTs bs rhss lthy
+  end;
+
+fun mk_fun_rec_thmss ctxt rec0_thmss (recs as rec1 :: _) rec_defs =
+  let
+    val f_Ts = binder_fun_types (fastype_of rec1);
+    val (fs, _) = mk_Frees "f" f_Ts ctxt;
+    val frecs = map (fn recx => Term.list_comb (recx, fs)) recs;
+
+    fun mk_ctrs_of (Type (T_name, As)) =
+      map (mk_ctr As) (#ctrs (the (ctr_sugar_of ctxt T_name)));
+
+    val fpTs = map (domain_type o body_fun_type o fastype_of) recs;
+    val fpTs_frecs = fpTs ~~ frecs;
+    val ctrss = map mk_ctrs_of fpTs;
+    val fss = unflat ctrss fs;
+
+    fun mk_rec_call g n (Type (@{type_name fun}, [dom_T, ran_T])) =
+        Abs (Name.uu, dom_T, mk_rec_call g (n + 1) ran_T)
+      | mk_rec_call g n fpT =
+        let
+          val frec = the (AList.lookup (op =) fpTs_frecs fpT);
+          val xg = Term.list_comb (g, map Bound (n - 1 downto 0));
+        in frec $ xg end;
+
+    fun mk_rec_arg_arg g_T g =
+      g :: (if exists_subtype_in fpTs g_T then [mk_rec_call g 0 g_T] else []);
+
+    fun mk_goal frec ctr f =
+      let
+        val g_Ts = binder_types (fastype_of ctr);
+        val (gs, _) = mk_Frees "g" g_Ts ctxt;
+        val gctr = Term.list_comb (ctr, gs);
+        val fgs = flat_rec_arg_args (map2 mk_rec_arg_arg g_Ts gs);
+      in
+        fold_rev (fold_rev Logic.all) [fs, gs]
+          (mk_Trueprop_eq (frec $ gctr, Term.list_comb (f, fgs)))
+      end;
+
+    fun mk_goals ctrs fs frec = map2 (mk_goal frec) ctrs fs;
+
+    val goalss = map3 mk_goals ctrss fss frecs;
+
+    fun tac ctxt =
+      unfold_thms_tac ctxt (@{thms o_apply fst_conv snd_conv} @ rec_defs @ flat rec0_thmss) THEN
+      HEADGOAL (rtac refl);
+
+    fun prove goal =
+      Goal.prove_sorry ctxt [] [] goal (tac o #context)
+      |> Thm.close_derivation;
+  in
+    map (map prove) goalss
+  end;
+
+fun define_fun_rec_derive_thms induct inducts recs0 rec_thmss fpTs lthy =
+  let
+    val thy = Proof_Context.theory_of lthy;
+
+    (* imperfect: will not yield the expected theorem for functions taking a large number of
+       arguments *)
+    val repair_induct = unfold_thms lthy @{thms all_mem_range};
+
+    val induct' = repair_induct induct;
+    val inducts' = map repair_induct inducts;
+
+    val Cs = map ((fn TVar ((s, _), S) => TFree (s, S)) o body_type o fastype_of) recs0;
+    val recs = map2 (mk_co_rec thy Least_FP Cs) fpTs recs0;
+    val ((recs', rec'_defs), lthy') = define_fun_recs fpTs Cs recs lthy |>> split_list;
+    val rec'_thmss = mk_fun_rec_thmss lthy' rec_thmss recs' rec'_defs;
+  in
+    ((induct', inducts', recs', rec'_thmss), lthy')
+  end;
+
 fun reindex_desc desc =
   let
     val kks = map fst desc;
@@ -130,10 +267,10 @@
 
     val dest_dtyp = Old_Datatype_Aux.typ_of_dtyp descr;
 
-    val Ts = Old_Datatype_Aux.get_rec_types descr;
-    val nn = length Ts;
+    val fpTs' = Old_Datatype_Aux.get_rec_types descr;
+    val nn = length fpTs';
 
-    val fp_sugars0 = map (lfp_sugar_of o fst o dest_Type) Ts;
+    val fp_sugars0 = map (lfp_sugar_of o fst o dest_Type) fpTs';
     val ctr_Tsss = map (map (map dest_dtyp o snd) o #3 o snd) descr;
     val kkssss =
       map (map (map (fn Old_Datatype_Aux.DtRec kk => [kk] | _ => []) o snd) o #3 o snd) descr;
@@ -146,34 +283,47 @@
     val callssss =
       map2 (map2 (map2 (fn ctr_T => map (apply_comps (num_binder_types ctr_T))))) ctr_Tsss kkssss;
 
-    val b_names = Name.variant_list [] (map base_name_of_typ Ts);
-    val compat_b_names = map (prefix compatN) b_names;
+    val b_names = Name.variant_list [] (map base_name_of_typ fpTs');
+    val compat_b_names = map (prefix compat_N) b_names;
     val compat_bs = map Binding.name compat_b_names;
 
     val ((fp_sugars, (lfp_sugar_thms, _)), lthy') =
       if nn > nn_fp then
-        mutualize_fp_sugars Least_FP cliques compat_bs Ts callers callssss fp_sugars0 lthy
+        mutualize_fp_sugars Least_FP cliques compat_bs fpTs' callers callssss fp_sugars0 lthy
       else
         ((fp_sugars0, (NONE, NONE)), lthy);
 
-    val recs = map (fst o dest_Const o #co_rec) fp_sugars;
-    val rec_thms = maps #co_rec_thms fp_sugars;
-
     val {common_co_inducts = [induct], ...} :: _ = fp_sugars;
     val inducts = map (the_single o #co_inducts) fp_sugars;
 
+    val recs = map #co_rec fp_sugars;
+    val rec_thmss = map #co_rec_thms fp_sugars;
+
+    fun is_nested_rec_type (Type (@{type_name fun}, [_, T])) = member (op =) fpTs' (body_type T)
+      | is_nested_rec_type _ = false;
+
+    val ((induct', inducts', recs', rec'_thmss), lthy'') =
+      if nesting_pref = Unfold_Nesting andalso
+         exists (exists (exists is_nested_rec_type)) ctr_Tsss then
+        define_fun_rec_derive_thms induct inducts recs rec_thmss fpTs' lthy'
+      else
+        ((induct, inducts, recs, rec_thmss), lthy');
+
+    val rec'_names = map (fst o dest_Const) recs';
+    val rec'_thms = flat rec'_thmss;
+
     fun mk_info (kk, {T = Type (T_name0, _), ctr_sugar = {casex, exhaust, nchotomy, injects,
         distincts, case_thms, case_cong, case_cong_weak, split, split_asm, ...}, ...} : fp_sugar) =
       (T_name0,
-       {index = kk, descr = descr, inject = injects, distinct = distincts, induct = induct,
-        inducts = inducts, exhaust = exhaust, nchotomy = nchotomy, rec_names = recs,
-        rec_rewrites = rec_thms, case_name = fst (dest_Const casex), case_rewrites = case_thms,
+       {index = kk, descr = descr, inject = injects, distinct = distincts, induct = induct',
+        inducts = inducts', exhaust = exhaust, nchotomy = nchotomy, rec_names = rec'_names,
+        rec_rewrites = rec'_thms, case_name = fst (dest_Const casex), case_rewrites = case_thms,
         case_cong = case_cong, case_cong_weak = case_cong_weak, split = split,
         split_asm = split_asm});
 
     val infos = map_index mk_info (take nn_fp fp_sugars);
   in
-    (nn, b_names, compat_b_names, lfp_sugar_thms, infos, lthy')
+    (nn, b_names, compat_b_names, lfp_sugar_thms, infos, lthy'')
   end;
 
 fun infos_of_new_datatype_mutual_cluster lthy fpT_name =
@@ -298,7 +448,7 @@
         NONE => []
       | SOME ((induct_thms, induct_thm, induct_attrs), (rec_thmss, _)) =>
         let
-          val common_name = compatN ^ mk_common_name b_names;
+          val common_name = compat_N ^ mk_common_name b_names;
 
           val common_notes =
             (if nn > 1 then [(inductN, [induct_thm], induct_attrs)] else [])
--- a/src/HOL/Tools/BNF/bnf_lfp_rec_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/BNF/bnf_lfp_rec_sugar.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -194,7 +194,7 @@
 
     fun mk_spec ctr_offset
         ({T, fp_res_index, ctr_sugar = {ctrs, ...}, recx, rec_thms, ...} : basic_lfp_sugar) =
-      {recx = mk_co_rec thy Least_FP (substAT T) perm_Cs' recx,
+      {recx = mk_co_rec thy Least_FP perm_Cs' (substAT T) recx,
        fp_nesting_map_ident0s = fp_nesting_map_ident0s, fp_nesting_map_comps = fp_nesting_map_comps,
        ctr_specs = mk_ctr_specs fp_res_index ctr_offset ctrs rec_thms};
   in
--- a/src/HOL/Tools/Old_Datatype/old_datatype_aux.ML	Mon Sep 08 14:03:01 2014 +0200
+++ b/src/HOL/Tools/Old_Datatype/old_datatype_aux.ML	Mon Sep 08 14:03:01 2014 +0200
@@ -331,7 +331,8 @@
     fun get_dt_descr T i tname dts =
       (case Symtab.lookup dt_info tname of
         NONE =>
-          typ_error T (quote tname ^ " is not a datatype - can't use it in nested recursion")
+          typ_error T (quote tname ^ " is not registered as an old-style datatype and hence cannot \
+            \be used in nested recursion")
       | SOME {index, descr, ...} =>
           let
             val (_, vars, _) = the (AList.lookup (op =) descr index);