src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML
changeset 69593 3dda49e08b9d
parent 66251 cd935b7cb3fb
child 69597 ff784d5a5bfb
equal deleted inserted replaced
69592:a80d8ec6c998 69593:3dda49e08b9d
   120 
   120 
   121 val nitpicksimp_attrs = @{attributes [nitpick_simp]};
   121 val nitpicksimp_attrs = @{attributes [nitpick_simp]};
   122 val simp_attrs = @{attributes [simp]};
   122 val simp_attrs = @{attributes [simp]};
   123 
   123 
   124 fun use_primcorecursive () =
   124 fun use_primcorecursive () =
   125   error ("\"auto\" failed (try " ^ quote (#1 @{command_keyword primcorecursive}) ^ " instead of " ^
   125   error ("\"auto\" failed (try " ^ quote (#1 \<^command_keyword>\<open>primcorecursive\<close>) ^ " instead of " ^
   126     quote (#1 @{command_keyword primcorec}) ^ ")");
   126     quote (#1 \<^command_keyword>\<open>primcorec\<close>) ^ ")");
   127 
   127 
   128 datatype corec_option =
   128 datatype corec_option =
   129   Plugins_Option of Proof.context -> Plugin_Name.filter |
   129   Plugins_Option of Proof.context -> Plugin_Name.filter |
   130   Sequential_Option |
   130   Sequential_Option |
   131   Exhaustive_Option |
   131   Exhaustive_Option |
   182     abs 0
   182     abs 0
   183   end;
   183   end;
   184 
   184 
   185 val abs_tuple_balanced = HOLogic.tupled_lambda o mk_tuple_balanced;
   185 val abs_tuple_balanced = HOLogic.tupled_lambda o mk_tuple_balanced;
   186 
   186 
   187 fun curried_type (Type (@{type_name fun}, [Type (@{type_name prod}, Ts), T])) =
   187 fun curried_type (Type (\<^type_name>\<open>fun\<close>, [Type (\<^type_name>\<open>prod\<close>, Ts), T])) =
   188   Ts ---> T;
   188   Ts ---> T;
   189 
   189 
   190 fun sort_list_duplicates xs = map snd (sort (int_ord o apply2 fst) xs);
   190 fun sort_list_duplicates xs = map snd (sort (int_ord o apply2 fst) xs);
   191 
   191 
   192 val mk_conjs = try (foldr1 HOLogic.mk_conj) #> the_default @{const True};
   192 val mk_conjs = try (foldr1 HOLogic.mk_conj) #> the_default @{const True};
   239   let
   239   let
   240     val thy = Proof_Context.theory_of ctxt;
   240     val thy = Proof_Context.theory_of ctxt;
   241 
   241 
   242     fun fld conds t =
   242     fun fld conds t =
   243       (case Term.strip_comb t of
   243       (case Term.strip_comb t of
   244         (Const (@{const_name Let}, _), [_, _]) => fld conds (unfold_lets_splits t)
   244         (Const (\<^const_name>\<open>Let\<close>, _), [_, _]) => fld conds (unfold_lets_splits t)
   245       | (Const (@{const_name If}, _), [cond, then_branch, else_branch]) =>
   245       | (Const (\<^const_name>\<open>If\<close>, _), [cond, then_branch, else_branch]) =>
   246         fld (conds @ conjuncts_s cond) then_branch o fld (conds @ s_not_conj [cond]) else_branch
   246         fld (conds @ conjuncts_s cond) then_branch o fld (conds @ s_not_conj [cond]) else_branch
   247       | (Const (c, _), args as _ :: _ :: _) =>
   247       | (Const (c, _), args as _ :: _ :: _) =>
   248         let val n = num_binder_types (Sign.the_const_type thy c) - 1 in
   248         let val n = num_binder_types (Sign.the_const_type thy c) - 1 in
   249           if n >= 0 andalso n < length args then
   249           if n >= 0 andalso n < length args then
   250             (case fastype_of1 (bound_Ts, nth args n) of
   250             (case fastype_of1 (bound_Ts, nth args n) of
   280           Abs (Name.uu, T, massage_abs (T :: bound_Ts) (m - 1) (incr_boundvars 1 t $ Bound 0))
   280           Abs (Name.uu, T, massage_abs (T :: bound_Ts) (m - 1) (incr_boundvars 1 t $ Bound 0))
   281         end
   281         end
   282     and massage_rec bound_Ts t =
   282     and massage_rec bound_Ts t =
   283       let val typof = curry fastype_of1 bound_Ts in
   283       let val typof = curry fastype_of1 bound_Ts in
   284         (case Term.strip_comb t of
   284         (case Term.strip_comb t of
   285           (Const (@{const_name Let}, _), [_, _]) => massage_rec bound_Ts (unfold_lets_splits t)
   285           (Const (\<^const_name>\<open>Let\<close>, _), [_, _]) => massage_rec bound_Ts (unfold_lets_splits t)
   286         | (Const (@{const_name If}, _), obj :: (branches as [_, _])) =>
   286         | (Const (\<^const_name>\<open>If\<close>, _), obj :: (branches as [_, _])) =>
   287           (case List.partition Term.is_dummy_pattern (map (massage_rec bound_Ts) branches) of
   287           (case List.partition Term.is_dummy_pattern (map (massage_rec bound_Ts) branches) of
   288             (dummy_branch' :: _, []) => dummy_branch'
   288             (dummy_branch' :: _, []) => dummy_branch'
   289           | (_, [branch']) => branch'
   289           | (_, [branch']) => branch'
   290           | (_, branches') =>
   290           | (_, branches') =>
   291             Term.list_comb (If_const (typof (hd branches')) $ tap (check_no_call bound_Ts) obj,
   291             Term.list_comb (If_const (typof (hd branches')) $ tap (check_no_call bound_Ts) obj,
   292               branches'))
   292               branches'))
   293         | (c as Const (@{const_name case_prod}, _), arg :: args) =>
   293         | (c as Const (\<^const_name>\<open>case_prod\<close>, _), arg :: args) =>
   294           massage_rec bound_Ts
   294           massage_rec bound_Ts
   295             (unfold_splits_lets (Term.list_comb (c $ Envir.eta_long bound_Ts arg, args)))
   295             (unfold_splits_lets (Term.list_comb (c $ Envir.eta_long bound_Ts arg, args)))
   296         | (Const (c, _), args as _ :: _ :: _) =>
   296         | (Const (c, _), args as _ :: _ :: _) =>
   297           (case try strip_fun_type (Sign.the_const_type thy c) of
   297           (case try strip_fun_type (Sign.the_const_type thy c) of
   298             SOME (gen_branch_Ts, gen_body_fun_T) =>
   298             SOME (gen_branch_Ts, gen_body_fun_T) =>
   331         | _ => massage_leaf bound_Ts t)
   331         | _ => massage_leaf bound_Ts t)
   332       end;
   332       end;
   333   in
   333   in
   334     massage_rec bound_Ts t0
   334     massage_rec bound_Ts t0
   335     |> Term.map_aterms (fn t =>
   335     |> Term.map_aterms (fn t =>
   336       if Term.is_dummy_pattern t then Const (@{const_name undefined}, fastype_of t) else t)
   336       if Term.is_dummy_pattern t then Const (\<^const_name>\<open>undefined\<close>, fastype_of t) else t)
   337   end;
   337   end;
   338 
   338 
   339 fun massage_let_if_case_corec ctxt has_call massage_leaf bound_Ts t0 =
   339 fun massage_let_if_case_corec ctxt has_call massage_leaf bound_Ts t0 =
   340   massage_let_if_case ctxt has_call massage_leaf (K (unexpected_corec_call_in ctxt [t0]))
   340   massage_let_if_case ctxt has_call massage_leaf (K (unexpected_corec_call_in ctxt [t0]))
   341     (K (unsupported_case_around_corec_call ctxt [t0])) bound_Ts t0;
   341     (K (unsupported_case_around_corec_call ctxt [t0])) bound_Ts t0;
   342 
   342 
   343 fun massage_nested_corec_call ctxt has_call massage_call massage_noncall bound_Ts U T t0 =
   343 fun massage_nested_corec_call ctxt has_call massage_call massage_noncall bound_Ts U T t0 =
   344   let
   344   let
   345     fun check_no_call t = if has_call t then unexpected_corec_call_in ctxt [t0] t else ();
   345     fun check_no_call t = if has_call t then unexpected_corec_call_in ctxt [t0] t else ();
   346 
   346 
   347     fun massage_mutual_call bound_Ts (Type (@{type_name fun}, [_, U2]))
   347     fun massage_mutual_call bound_Ts (Type (\<^type_name>\<open>fun\<close>, [_, U2]))
   348         (Type (@{type_name fun}, [T1, T2])) t =
   348         (Type (\<^type_name>\<open>fun\<close>, [T1, T2])) t =
   349         Abs (Name.uu, T1, massage_mutual_call (T1 :: bound_Ts) U2 T2 (incr_boundvars 1 t $ Bound 0))
   349         Abs (Name.uu, T1, massage_mutual_call (T1 :: bound_Ts) U2 T2 (incr_boundvars 1 t $ Bound 0))
   350       | massage_mutual_call bound_Ts U T t =
   350       | massage_mutual_call bound_Ts U T t =
   351         (if has_call t then massage_call else massage_noncall) bound_Ts U T t;
   351         (if has_call t then massage_call else massage_noncall) bound_Ts U T t;
   352 
   352 
   353     fun massage_map bound_Ts (Type (_, Us)) (Type (s, Ts)) t =
   353     fun massage_map bound_Ts (Type (_, Us)) (Type (s, Ts)) t =
   377         fun massage_body () =
   377         fun massage_body () =
   378           Term.lambda var (Term.incr_boundvars 1 (massage_any_call bound_Ts U T
   378           Term.lambda var (Term.incr_boundvars 1 (massage_any_call bound_Ts U T
   379             (betapply (t, var))));
   379             (betapply (t, var))));
   380       in
   380       in
   381         (case t of
   381         (case t of
   382           Const (@{const_name comp}, _) $ t1 $ t2 =>
   382           Const (\<^const_name>\<open>comp\<close>, _) $ t1 $ t2 =>
   383           if has_call t2 then massage_body ()
   383           if has_call t2 then massage_body ()
   384           else mk_comp bound_Ts (massage_mutual_fun bound_Ts U T t1, t2)
   384           else mk_comp bound_Ts (massage_mutual_fun bound_Ts U T t1, t2)
   385         | _ => massage_body ())
   385         | _ => massage_body ())
   386       end
   386       end
   387     and massage_any_call bound_Ts U T =
   387     and massage_any_call bound_Ts U T =
   400                 Term.list_comb (f',
   400                 Term.list_comb (f',
   401                   @{map 3} (massage_any_call bound_Ts) (binder_types f'_T) arg_Ts args)
   401                   @{map 3} (massage_any_call bound_Ts) (binder_types f'_T) arg_Ts args)
   402               end
   402               end
   403             | NONE =>
   403             | NONE =>
   404               (case t of
   404               (case t of
   405                 Const (@{const_name case_prod}, _) $ t' =>
   405                 Const (\<^const_name>\<open>case_prod\<close>, _) $ t' =>
   406                 let
   406                 let
   407                   val U' = curried_type U;
   407                   val U' = curried_type U;
   408                   val T' = curried_type T;
   408                   val T' = curried_type T;
   409                 in
   409                 in
   410                   Const (@{const_name case_prod}, U' --> U) $ massage_any_call bound_Ts U' T' t'
   410                   Const (\<^const_name>\<open>case_prod\<close>, U' --> U) $ massage_any_call bound_Ts U' T' t'
   411                 end
   411                 end
   412               | t1 $ t2 =>
   412               | t1 $ t2 =>
   413                 (if has_call t2 then
   413                 (if has_call t2 then
   414                    massage_mutual_call bound_Ts U T t
   414                    massage_mutual_call bound_Ts U T t
   415                  else
   415                  else
   553     val substAT = Term.typ_subst_TVars As_rho;
   553     val substAT = Term.typ_subst_TVars As_rho;
   554     val substCT = Term.typ_subst_TVars Cs_rho;
   554     val substCT = Term.typ_subst_TVars Cs_rho;
   555 
   555 
   556     val perm_Cs' = map substCT perm_Cs;
   556     val perm_Cs' = map substCT perm_Cs;
   557 
   557 
   558     fun call_of nullary [] [g_i] [Type (@{type_name fun}, [_, T])] =
   558     fun call_of nullary [] [g_i] [Type (\<^type_name>\<open>fun\<close>, [_, T])] =
   559         (if exists_subtype_in Cs T then Nested_Corec
   559         (if exists_subtype_in Cs T then Nested_Corec
   560          else if nullary then Dummy_No_Corec
   560          else if nullary then Dummy_No_Corec
   561          else No_Corec) g_i
   561          else No_Corec) g_i
   562       | call_of _ [q_i] [g_i, g_i'] _ = Mutual_Corec (q_i, g_i, g_i');
   562       | call_of _ [q_i] [g_i, g_i'] _ = Mutual_Corec (q_i, g_i, g_i');
   563 
   563 
   593      co_induct_of common_coinduct_thms, strong_co_induct_of common_coinduct_thms,
   593      co_induct_of common_coinduct_thms, strong_co_induct_of common_coinduct_thms,
   594      co_induct_of coinduct_thmss, strong_co_induct_of coinduct_thmss, coinduct_attrs_pair,
   594      co_induct_of coinduct_thmss, strong_co_induct_of coinduct_thmss, coinduct_attrs_pair,
   595      is_some gfp_sugar_thms, lthy)
   595      is_some gfp_sugar_thms, lthy)
   596   end;
   596   end;
   597 
   597 
   598 val undef_const = Const (@{const_name undefined}, dummyT);
   598 val undef_const = Const (\<^const_name>\<open>undefined\<close>, dummyT);
   599 
   599 
   600 type coeqn_data_disc =
   600 type coeqn_data_disc =
   601   {fun_name: string,
   601   {fun_name: string,
   602    fun_T: typ,
   602    fun_T: typ,
   603    fun_args: term list,
   603    fun_args: term list,
   674     val (sequential, basic_ctr_specs) =
   674     val (sequential, basic_ctr_specs) =
   675       the (AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name);
   675       the (AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name);
   676 
   676 
   677     val discs = map #disc basic_ctr_specs;
   677     val discs = map #disc basic_ctr_specs;
   678     val ctrs = map #ctr basic_ctr_specs;
   678     val ctrs = map #ctr basic_ctr_specs;
   679     val not_disc = head_of concl = @{term Not};
   679     val not_disc = head_of concl = \<^term>\<open>Not\<close>;
   680     val _ = not_disc andalso length ctrs <> 2 andalso
   680     val _ = not_disc andalso length ctrs <> 2 andalso
   681       error_at ctxt [concl] "Negated discriminator for a type with \<noteq> 2 constructors";
   681       error_at ctxt [concl] "Negated discriminator for a type with \<noteq> 2 constructors";
   682     val disc' = find_subterm (member (op =) discs o head_of) concl;
   682     val disc' = find_subterm (member (op =) discs o head_of) concl;
   683     val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd)
   683     val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd)
   684       |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in
   684       |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in
   892     NONE => (I, I, I)
   892     NONE => (I, I, I)
   893   | SOME {fun_args, rhs_term, ... } =>
   893   | SOME {fun_args, rhs_term, ... } =>
   894     let
   894     let
   895       val bound_Ts = List.rev (map fastype_of fun_args);
   895       val bound_Ts = List.rev (map fastype_of fun_args);
   896 
   896 
   897       fun rewrite_stop _ t = if has_call t then @{term False} else @{term True};
   897       fun rewrite_stop _ t = if has_call t then \<^term>\<open>False\<close> else \<^term>\<open>True\<close>;
   898       fun rewrite_end _ t = if has_call t then undef_const else t;
   898       fun rewrite_end _ t = if has_call t then undef_const else t;
   899       fun rewrite_cont bound_Ts t =
   899       fun rewrite_cont bound_Ts t =
   900         if has_call t then mk_tuple1_balanced bound_Ts (snd (strip_comb t)) else undef_const;
   900         if has_call t then mk_tuple1_balanced bound_Ts (snd (strip_comb t)) else undef_const;
   901       fun massage f _ = massage_let_if_case_corec ctxt has_call f bound_Ts rhs_term
   901       fun massage f _ = massage_let_if_case_corec ctxt has_call f bound_Ts rhs_term
   902         |> abs_tuple_balanced fun_args;
   902         |> abs_tuple_balanced fun_args;
   919           fun rewrite bound_Ts (Abs (s, T', t')) = Abs (s, T', rewrite (T' :: bound_Ts) t')
   919           fun rewrite bound_Ts (Abs (s, T', t')) = Abs (s, T', rewrite (T' :: bound_Ts) t')
   920             | rewrite bound_Ts (t as _ $ _) =
   920             | rewrite bound_Ts (t as _ $ _) =
   921               let val (u, vs) = strip_comb t in
   921               let val (u, vs) = strip_comb t in
   922                 if is_Free u andalso has_call u then
   922                 if is_Free u andalso has_call u then
   923                   Inr_const T U2 $ mk_tuple1_balanced bound_Ts vs
   923                   Inr_const T U2 $ mk_tuple1_balanced bound_Ts vs
   924                 else if try (fst o dest_Const) u = SOME @{const_name case_prod} then
   924                 else if try (fst o dest_Const) u = SOME \<^const_name>\<open>case_prod\<close> then
   925                   map (rewrite bound_Ts) vs |> chop 1
   925                   map (rewrite bound_Ts) vs |> chop 1
   926                   |>> HOLogic.mk_case_prod o the_single
   926                   |>> HOLogic.mk_case_prod o the_single
   927                   |> Term.list_comb
   927                   |> Term.list_comb
   928                 else
   928                 else
   929                   Term.list_comb (rewrite bound_Ts u, map (rewrite bound_Ts) vs)
   929                   Term.list_comb (rewrite bound_Ts u, map (rewrite bound_Ts) vs)
   972     val corecs = map #corec corec_specs;
   972     val corecs = map #corec corec_specs;
   973     val ctr_specss = map #ctr_specs corec_specs;
   973     val ctr_specss = map #ctr_specs corec_specs;
   974     val corec_args = hd corecs
   974     val corec_args = hd corecs
   975       |> fst o split_last o binder_types o fastype_of
   975       |> fst o split_last o binder_types o fastype_of
   976       |> map (fn T =>
   976       |> map (fn T =>
   977           if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, @{term False})
   977           if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, \<^term>\<open>False\<close>)
   978           else Const (@{const_name undefined}, T))
   978           else Const (\<^const_name>\<open>undefined\<close>, T))
   979       |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss
   979       |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss
   980       |> fold2 (fold o build_corec_args_sel ctxt has_call) sel_eqnss ctr_specss;
   980       |> fold2 (fold o build_corec_args_sel ctxt has_call) sel_eqnss ctr_specss;
   981 
   981 
   982     val bad = fold (add_extra_frees ctxt [] []) corec_args [];
   982     val bad = fold (add_extra_frees ctxt [] []) corec_args [];
   983     val _ = null bad orelse
   983     val _ = null bad orelse
  1243           map2 (fn excludes => mk_excludesss excludes o length o #ctr_specs)
  1243           map2 (fn excludes => mk_excludesss excludes o length o #ctr_specs)
  1244             (map2 append excludess' taut_thmss) corec_specs;
  1244             (map2 append excludess' taut_thmss) corec_specs;
  1245 
  1245 
  1246         fun prove_disc ({ctr_specs, ...} : corec_spec) excludesss
  1246         fun prove_disc ({ctr_specs, ...} : corec_spec) excludesss
  1247             ({fun_name, fun_T, fun_args, ctr_no, prems, eqn_pos, ...} : coeqn_data_disc) =
  1247             ({fun_name, fun_T, fun_args, ctr_no, prems, eqn_pos, ...} : coeqn_data_disc) =
  1248           if Term.aconv_untyped (#disc (nth ctr_specs ctr_no), @{term "\<lambda>x. x = x"}) then
  1248           if Term.aconv_untyped (#disc (nth ctr_specs ctr_no), \<^term>\<open>\<lambda>x. x = x\<close>) then
  1249             []
  1249             []
  1250           else
  1250           else
  1251             let
  1251             let
  1252               val {disc, corec_disc, ...} = nth ctr_specs ctr_no;
  1252               val {disc, corec_disc, ...} = nth ctr_specs ctr_no;
  1253               val k = 1 + ctr_no;
  1253               val k = 1 + ctr_no;
  1257                 |> curry betapply disc
  1257                 |> curry betapply disc
  1258                 |> HOLogic.mk_Trueprop
  1258                 |> HOLogic.mk_Trueprop
  1259                 |> curry Logic.list_implies (map HOLogic.mk_Trueprop prems)
  1259                 |> curry Logic.list_implies (map HOLogic.mk_Trueprop prems)
  1260                 |> curry Logic.list_all (map dest_Free fun_args);
  1260                 |> curry Logic.list_all (map dest_Free fun_args);
  1261             in
  1261             in
  1262               if prems = [@{term False}] then
  1262               if prems = [\<^term>\<open>False\<close>] then
  1263                 []
  1263                 []
  1264               else
  1264               else
  1265                 Goal.prove_sorry lthy [] [] goal
  1265                 Goal.prove_sorry lthy [] [] goal
  1266                   (fn {context = ctxt, prems = _} =>
  1266                   (fn {context = ctxt, prems = _} =>
  1267                     mk_primcorec_disc_tac ctxt def_thms corec_disc k m excludesss)
  1267                     mk_primcorec_disc_tac ctxt def_thms corec_disc k m excludesss)
  1339                 |> curry Logic.list_implies (map HOLogic.mk_Trueprop prems)
  1339                 |> curry Logic.list_implies (map HOLogic.mk_Trueprop prems)
  1340                 |> curry Logic.list_all (map dest_Free fun_args);
  1340                 |> curry Logic.list_all (map dest_Free fun_args);
  1341               val disc_thm_opt = AList.lookup (op =) disc_alist disc;
  1341               val disc_thm_opt = AList.lookup (op =) disc_alist disc;
  1342               val sel_thms = map (snd o snd) (filter (member (op =) sels o fst) sel_alist);
  1342               val sel_thms = map (snd o snd) (filter (member (op =) sels o fst) sel_alist);
  1343             in
  1343             in
  1344               if prems = [@{term False}] then
  1344               if prems = [\<^term>\<open>False\<close>] then
  1345                 []
  1345                 []
  1346               else
  1346               else
  1347                 Goal.prove_sorry lthy [] [] goal
  1347                 Goal.prove_sorry lthy [] [] goal
  1348                   (fn {context = ctxt, prems = _} =>
  1348                   (fn {context = ctxt, prems = _} =>
  1349                     mk_primcorec_ctr_tac ctxt m collapse disc_thm_opt sel_thms)
  1349                     mk_primcorec_ctr_tac ctxt m collapse disc_thm_opt sel_thms)
  1407                           andalso exists #auto_gen disc_eqns;
  1407                           andalso exists #auto_gen disc_eqns;
  1408                       val rhs =
  1408                       val rhs =
  1409                         (if exhaustive_code then
  1409                         (if exhaustive_code then
  1410                            split_last (map_filter I ctr_conds_argss_opt) ||> snd
  1410                            split_last (map_filter I ctr_conds_argss_opt) ||> snd
  1411                          else
  1411                          else
  1412                            Const (@{const_name Code.abort}, @{typ String.literal} -->
  1412                            Const (\<^const_name>\<open>Code.abort\<close>, \<^typ>\<open>String.literal\<close> -->
  1413                                (HOLogic.unitT --> body_type fun_T) --> body_type fun_T) $
  1413                                (HOLogic.unitT --> body_type fun_T) --> body_type fun_T) $
  1414                              HOLogic.mk_literal fun_name $
  1414                              HOLogic.mk_literal fun_name $
  1415                              absdummy HOLogic.unitT (incr_boundvars 1 lhs)
  1415                              absdummy HOLogic.unitT (incr_boundvars 1 lhs)
  1416                            |> pair (map_filter I ctr_conds_argss_opt))
  1416                            |> pair (map_filter I ctr_conds_argss_opt))
  1417                          |-> fold_rev (fn (prems, u) => mk_If (s_conjs prems) u)
  1417                          |-> fold_rev (fn (prems, u) => mk_If (s_conjs prems) u)
  1585    || Parse.reserved "transfer" >> K Transfer_Option);
  1585    || Parse.reserved "transfer" >> K Transfer_Option);
  1586 
  1586 
  1587 val where_alt_props_of_parser = Parse.where_ |-- Parse.!!! (Parse.enum1 "|"
  1587 val where_alt_props_of_parser = Parse.where_ |-- Parse.!!! (Parse.enum1 "|"
  1588   ((Parse.prop >> pair Binding.empty_atts) -- Scan.option (Parse.reserved "of" |-- Parse.const)));
  1588   ((Parse.prop >> pair Binding.empty_atts) -- Scan.option (Parse.reserved "of" |-- Parse.const)));
  1589 
  1589 
  1590 val _ = Outer_Syntax.local_theory_to_proof @{command_keyword primcorecursive}
  1590 val _ = Outer_Syntax.local_theory_to_proof \<^command_keyword>\<open>primcorecursive\<close>
  1591   "define primitive corecursive functions"
  1591   "define primitive corecursive functions"
  1592   ((Scan.optional (@{keyword "("} |--
  1592   ((Scan.optional (\<^keyword>\<open>(\<close> |--
  1593       Parse.!!! (Parse.list1 corec_option_parser) --| @{keyword ")"}) []) --
  1593       Parse.!!! (Parse.list1 corec_option_parser) --| \<^keyword>\<open>)\<close>) []) --
  1594     (Parse.vars -- where_alt_props_of_parser) >> uncurry (primcorecursive_cmd true));
  1594     (Parse.vars -- where_alt_props_of_parser) >> uncurry (primcorecursive_cmd true));
  1595 
  1595 
  1596 val _ = Outer_Syntax.local_theory @{command_keyword primcorec}
  1596 val _ = Outer_Syntax.local_theory \<^command_keyword>\<open>primcorec\<close>
  1597   "define primitive corecursive functions"
  1597   "define primitive corecursive functions"
  1598   ((Scan.optional (@{keyword "("} |-- Parse.!!! (Parse.list1 corec_option_parser)
  1598   ((Scan.optional (\<^keyword>\<open>(\<close> |-- Parse.!!! (Parse.list1 corec_option_parser)
  1599       --| @{keyword ")"}) []) --
  1599       --| \<^keyword>\<open>)\<close>) []) --
  1600     (Parse.vars -- where_alt_props_of_parser) >> uncurry (primcorec_cmd true));
  1600     (Parse.vars -- where_alt_props_of_parser) >> uncurry (primcorec_cmd true));
  1601 
  1601 
  1602 val _ = Theory.setup (gfp_rec_sugar_interpretation transfer_plugin
  1602 val _ = Theory.setup (gfp_rec_sugar_interpretation transfer_plugin
  1603   gfp_rec_sugar_transfer_interpretation);
  1603   gfp_rec_sugar_transfer_interpretation);
  1604 
  1604