src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML
changeset 56152 2a31945b9a58
parent 55969 8820ddb8f9f4
child 56254 a2dd9200854d
equal deleted inserted replaced
56132:64eeda68e693 56152:2a31945b9a58
   519 
   519 
   520 datatype coeqn_data =
   520 datatype coeqn_data =
   521   Disc of coeqn_data_disc |
   521   Disc of coeqn_data_disc |
   522   Sel of coeqn_data_sel;
   522   Sel of coeqn_data_sel;
   523 
   523 
   524 fun dissect_coeqn_disc fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list)
   524 fun check_extra_variables lthy vars names eqn =
       
   525   let val b = fold_aterms (fn x as Free (v, _) =>
       
   526     if (not (member (op =) vars x) andalso
       
   527       not (member (op =) names v) andalso
       
   528       v <> Name.uu_ andalso
       
   529       not (Variable.is_fixed lthy v)) then cons x else I | _ => I) eqn []
       
   530   in
       
   531     null b orelse
       
   532     primcorec_error_eqn ("extra variable(s) in equation: " ^
       
   533       commas (map (Syntax.string_of_term lthy) b)) eqn
       
   534   end;
       
   535 
       
   536 fun dissect_coeqn_disc lthy fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list)
   525     eqn_pos ctr_rhs_opt code_rhs_opt prems' concl matchedsss =
   537     eqn_pos ctr_rhs_opt code_rhs_opt prems' concl matchedsss =
   526   let
   538   let
   527     fun find_subterm p =
   539     fun find_subterm p =
   528       let (* FIXME \<exists>? *)
   540       let (* FIXME \<exists>? *)
   529         fun find (t as u $ v) = if p t then SOME t else merge_options (find u, find v)
   541         fun find (t as u $ v) = if p t then SOME t else merge_options (find u, find v)
   533     val applied_fun = concl
   545     val applied_fun = concl
   534       |> find_subterm (member (op = o apsnd SOME) fun_names o try (fst o dest_Free o head_of))
   546       |> find_subterm (member (op = o apsnd SOME) fun_names o try (fst o dest_Free o head_of))
   535       |> the
   547       |> the
   536       handle Option.Option => primcorec_error_eqn "malformed discriminator formula" concl;
   548       handle Option.Option => primcorec_error_eqn "malformed discriminator formula" concl;
   537     val ((fun_name, fun_T), fun_args) = strip_comb applied_fun |>> dest_Free;
   549     val ((fun_name, fun_T), fun_args) = strip_comb applied_fun |>> dest_Free;
       
   550 
       
   551     val _ = let val fixeds = filter (Variable.is_fixed lthy o fst o dest_Free) fun_args in
       
   552         null fixeds orelse primcorec_error_eqns "function argument(s) are fixed in context" fixeds
       
   553       end;
       
   554 
       
   555     val _ =
       
   556       let
       
   557         val bad = prems'
       
   558           |> filter (exists_subterm (fn Free (v, _) => member (op =) fun_names v | _ => false))
       
   559       in
       
   560         null bad orelse primcorec_error_eqns "corecursive call(s) in condition(s)" bad
       
   561       end;
       
   562 
       
   563     val _ = forall is_Free fun_args orelse
       
   564       primcorec_error_eqn ("non-variable function argument \"" ^
       
   565         Syntax.string_of_term lthy (find_first (not o is_Free) fun_args |> the) ^
       
   566           "\" (pattern matching is not supported by primcorec(ursive))") applied_fun
       
   567 
       
   568     val _ = let val d = duplicates (op =) fun_args in null d orelse
       
   569       primcorec_error_eqn ("duplicate variable \"" ^ Syntax.string_of_term lthy (hd d) ^ "\"")
       
   570         applied_fun end;
       
   571 
   538     val SOME (sequential, basic_ctr_specs) =
   572     val SOME (sequential, basic_ctr_specs) =
   539       AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name;
   573       AList.lookup (op =) (fun_names ~~ (sequentials ~~ basic_ctr_specss)) fun_name;
   540 
   574 
   541     val discs = map #disc basic_ctr_specs;
   575     val discs = map #disc basic_ctr_specs;
   542     val ctrs = map #ctr basic_ctr_specs;
   576     val ctrs = map #ctr basic_ctr_specs;
   545       primcorec_error_eqn "negated discriminator for a type with \<noteq> 2 constructors" concl;
   579       primcorec_error_eqn "negated discriminator for a type with \<noteq> 2 constructors" concl;
   546     val disc' = find_subterm (member (op =) discs o head_of) concl;
   580     val disc' = find_subterm (member (op =) discs o head_of) concl;
   547     val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd)
   581     val eq_ctr0 = concl |> perhaps (try HOLogic.dest_not) |> try (HOLogic.dest_eq #> snd)
   548         |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in
   582         |> (fn SOME t => let val n = find_index (curry (op =) t) ctrs in
   549           if n >= 0 then SOME n else NONE end | _ => NONE);
   583           if n >= 0 then SOME n else NONE end | _ => NONE);
       
   584 
       
   585     val _ = if is_some disc' andalso perhaps (try HOLogic.dest_not) concl <> the disc'
       
   586       then primcorec_error_eqn "malformed discriminator formula" concl else ();
       
   587 
       
   588 
   550     val _ = is_some disc' orelse is_some eq_ctr0 orelse
   589     val _ = is_some disc' orelse is_some eq_ctr0 orelse
   551       primcorec_error_eqn "no discriminator in equation" concl;
   590       primcorec_error_eqn "no discriminator in equation" concl;
   552     val ctr_no' =
   591     val ctr_no' =
   553       if is_none disc' then the eq_ctr0 else find_index (curry (op =) (head_of (the disc'))) discs;
   592       if is_none disc' then the eq_ctr0 else find_index (curry (op =) (head_of (the disc'))) discs;
   554     val ctr_no = if not_disc then 1 - ctr_no' else ctr_no';
   593     val ctr_no = if not_disc then 1 - ctr_no' else ctr_no';
   566 
   605 
   567     val user_eqn =
   606     val user_eqn =
   568       (actual_prems, concl)
   607       (actual_prems, concl)
   569       |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args)
   608       |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args)
   570       |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies;
   609       |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies;
       
   610 
       
   611     val _ = check_extra_variables lthy fun_args fun_names user_eqn;
   571   in
   612   in
   572     (Disc {
   613     (Disc {
   573       fun_name = fun_name,
   614       fun_name = fun_name,
   574       fun_T = fun_T,
   615       fun_T = fun_T,
   575       fun_args = fun_args,
   616       fun_args = fun_args,
   583       eqn_pos = eqn_pos,
   624       eqn_pos = eqn_pos,
   584       user_eqn = user_eqn
   625       user_eqn = user_eqn
   585     }, matchedsss')
   626     }, matchedsss')
   586   end;
   627   end;
   587 
   628 
   588 fun dissect_coeqn_sel fun_names (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos
   629 fun dissect_coeqn_sel lthy fun_names (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos
   589     ctr_rhs_opt code_rhs_opt eqn0 of_spec_opt eqn =
   630     ctr_rhs_opt code_rhs_opt eqn0 of_spec_opt eqn =
   590   let
   631   let
   591     val (lhs, rhs) = HOLogic.dest_eq eqn
   632     val (lhs, rhs) = HOLogic.dest_eq eqn
   592       handle TERM _ =>
   633       handle TERM _ =>
   593              primcorec_error_eqn "malformed function equation (expected \"lhs = rhs\")" eqn;
   634              primcorec_error_eqn "malformed function equation (expected \"lhs = rhs\")" eqn;
   594     val sel = head_of lhs;
   635     val sel = head_of lhs;
   595     val ((fun_name, fun_T), fun_args) = dest_comb lhs |> snd |> strip_comb |> apfst dest_Free
   636     val ((fun_name, fun_T), fun_args) = dest_comb lhs |> snd |> strip_comb |> apfst dest_Free
   596       handle TERM _ =>
   637       handle TERM _ =>
   597              primcorec_error_eqn "malformed selector argument in left-hand side" eqn;
   638              primcorec_error_eqn "malformed selector argument in left-hand side" eqn;
       
   639 
       
   640     val _ = let val fixeds = filter (Variable.is_fixed lthy o fst o dest_Free) fun_args in
       
   641         null fixeds orelse primcorec_error_eqns "function argument(s) are fixed in context" fixeds
       
   642       end;
       
   643 
   598     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name)
   644     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name)
   599       handle Option.Option =>
   645       handle Option.Option =>
   600              primcorec_error_eqn "malformed selector argument in left-hand side" eqn;
   646              primcorec_error_eqn "malformed selector argument in left-hand side" eqn;
   601     val {ctr, ...} =
   647     val {ctr, ...} =
   602       (case of_spec_opt of
   648       (case of_spec_opt of
   603         SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs)
   649         SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs)
   604       | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single
   650       | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single
   605           handle List.Empty => primcorec_error_eqn "ambiguous selector - use \"of\"" eqn);
   651           handle List.Empty => primcorec_error_eqn "ambiguous selector - use \"of\"" eqn);
   606     val user_eqn = drop_all eqn0;
   652     val user_eqn = drop_all eqn0;
       
   653 
       
   654     val _ = check_extra_variables lthy fun_args fun_names user_eqn;
   607   in
   655   in
   608     Sel {
   656     Sel {
   609       fun_name = fun_name,
   657       fun_name = fun_name,
   610       fun_T = fun_T,
   658       fun_T = fun_T,
   611       fun_args = fun_args,
   659       fun_args = fun_args,
   617       eqn_pos = eqn_pos,
   665       eqn_pos = eqn_pos,
   618       user_eqn = user_eqn
   666       user_eqn = user_eqn
   619     }
   667     }
   620   end;
   668   end;
   621 
   669 
   622 fun dissect_coeqn_ctr fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list)
   670 fun dissect_coeqn_ctr lthy fun_names sequentials (basic_ctr_specss : basic_corec_ctr_spec list list)
   623     eqn_pos eqn0 code_rhs_opt prems concl matchedsss =
   671     eqn_pos eqn0 code_rhs_opt prems concl matchedsss =
   624   let
   672   let
   625     val (lhs, rhs) = HOLogic.dest_eq concl;
   673     val (lhs, rhs) = HOLogic.dest_eq concl;
   626     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   674     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
       
   675 
       
   676     val _ = check_extra_variables lthy fun_args fun_names (drop_all eqn0);
       
   677 
   627     val SOME basic_ctr_specs = AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name;
   678     val SOME basic_ctr_specs = AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name;
   628     val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs);
   679     val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs);
   629     val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs)
   680     val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs)
   630       handle Option.Option => primcorec_error_eqn "not a constructor" ctr;
   681       handle Option.Option => primcorec_error_eqn "not a constructor" ctr;
   631 
   682 
   632     val disc_concl = betapply (disc, lhs);
   683     val disc_concl = betapply (disc, lhs);
   633     val (eqn_data_disc_opt, matchedsss') =
   684     val (eqn_data_disc_opt, matchedsss') =
   634       if null (tl basic_ctr_specs) then
   685       if null (tl basic_ctr_specs) then
   635         (NONE, matchedsss)
   686         (NONE, matchedsss)
   636       else
   687       else
   637         apfst SOME (dissect_coeqn_disc fun_names sequentials basic_ctr_specss eqn_pos
   688         apfst SOME (dissect_coeqn_disc lthy fun_names sequentials basic_ctr_specss eqn_pos
   638           (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt prems disc_concl matchedsss);
   689           (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt prems disc_concl matchedsss);
   639 
   690 
   640     val sel_concls = sels ~~ ctr_args
   691     val sel_concls = sels ~~ ctr_args
   641       |> map (fn (sel, ctr_arg) => HOLogic.mk_eq (betapply (sel, lhs), ctr_arg));
   692       |> map (fn (sel, ctr_arg) => HOLogic.mk_eq (betapply (sel, lhs), ctr_arg))
       
   693         handle UnequalLengths =>
       
   694           primcorec_error_eqn "partially applied constructor in right-hand side" rhs;
   642 
   695 
   643 (*
   696 (*
   644 val _ = tracing ("reduced\n    " ^ Syntax.string_of_term @{context} concl ^ "\nto\n    \<cdot> " ^
   697 val _ = tracing ("reduced\n    " ^ Syntax.string_of_term @{context} concl ^ "\nto\n    \<cdot> " ^
   645  (is_some eqn_data_disc_opt ? K (Syntax.string_of_term @{context} disc_concl ^ "\n    \<cdot> ")) "" ^
   698  (is_some eqn_data_disc_opt ? K (Syntax.string_of_term @{context} disc_concl ^ "\n    \<cdot> ")) "" ^
   646  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) sel_concls) ^
   699  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) sel_concls) ^
   647  "\nfor premise(s)\n    \<cdot> " ^
   700  "\nfor premise(s)\n    \<cdot> " ^
   648  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) prems));
   701  space_implode "\n    \<cdot> " (map (Syntax.string_of_term @{context}) prems));
   649 *)
   702 *)
   650 
   703 
   651     val eqns_data_sel =
   704     val eqns_data_sel =
   652       map (dissect_coeqn_sel fun_names basic_ctr_specss eqn_pos
   705       map (dissect_coeqn_sel lthy fun_names basic_ctr_specss eqn_pos
   653         (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt eqn0 (SOME ctr)) sel_concls;
   706         (SOME (abstract (List.rev fun_args) rhs)) code_rhs_opt eqn0 (SOME ctr)) sel_concls;
   654   in
   707   in
   655     (the_list eqn_data_disc_opt @ eqns_data_sel, matchedsss')
   708     (the_list eqn_data_disc_opt @ eqns_data_sel, matchedsss')
   656   end;
   709   end;
   657 
   710 
   658 fun dissect_coeqn_code lthy has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss =
   711 fun dissect_coeqn_code lthy has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss =
   659   let
   712   let
   660     val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs lthy has_call []);
   713     val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs lthy has_call []);
   661     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   714     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
       
   715 
       
   716     val _ = check_extra_variables lthy fun_args fun_names concl;
       
   717 
   662     val SOME basic_ctr_specs = AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name;
   718     val SOME basic_ctr_specs = AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name;
   663 
   719 
   664     val cond_ctrs = fold_rev_corec_code_rhs lthy (fn cs => fn ctr => fn _ =>
   720     val cond_ctrs = fold_rev_corec_code_rhs lthy (fn cs => fn ctr => fn _ =>
   665         if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs)
   721         if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs)
   666         else primcorec_error_eqn "not a constructor" ctr) [] rhs' []
   722         else primcorec_error_eqn "not a constructor" ctr) [] rhs' []
   674         |> curry Term.list_comb ctr
   730         |> curry Term.list_comb ctr
   675         |> curry HOLogic.mk_eq lhs);
   731         |> curry HOLogic.mk_eq lhs);
   676 
   732 
   677     val sequentials = replicate (length fun_names) false;
   733     val sequentials = replicate (length fun_names) false;
   678   in
   734   in
   679     fold_map2 (dissect_coeqn_ctr fun_names sequentials basic_ctr_specss eqn_pos eqn0
   735     fold_map2 (dissect_coeqn_ctr lthy fun_names sequentials basic_ctr_specss eqn_pos eqn0
   680         (SOME (abstract (List.rev fun_args) rhs)))
   736         (SOME (abstract (List.rev fun_args) rhs)))
   681       ctr_premss ctr_concls matchedsss
   737       ctr_premss ctr_concls matchedsss
   682   end;
   738   end;
   683 
   739 
   684 fun dissect_coeqn lthy has_call fun_names sequentials
   740 fun dissect_coeqn lthy has_call fun_names sequentials
   685     (basic_ctr_specss : basic_corec_ctr_spec list list) (eqn_pos, eqn0) of_spec_opt matchedsss =
   741     (basic_ctr_specss : basic_corec_ctr_spec list list) (eqn_pos, eqn0) of_spec_opt matchedsss =
   686   let
   742   let
   687     val eqn = drop_all eqn0
   743     val eqn = drop_all eqn0
   688       handle TERM _ => primcorec_error_eqn "malformed function equation" eqn0;
   744       handle TERM _ => primcorec_error_eqn "malformed function equation" eqn0;
   689     val (prems, concl) = Logic.strip_horn eqn
   745     val (prems, concl) = Logic.strip_horn eqn
   690       |> apfst (map HOLogic.dest_Trueprop) o apsnd HOLogic.dest_Trueprop;
   746       |> apfst (map HOLogic.dest_Trueprop) o apsnd HOLogic.dest_Trueprop
       
   747         handle TERM _ => primcorec_error_eqn "malformed function equation" eqn;
   691 
   748 
   692     val head = concl
   749     val head = concl
   693       |> perhaps (try HOLogic.dest_not) |> perhaps (try (fst o HOLogic.dest_eq))
   750       |> perhaps (try HOLogic.dest_not) |> perhaps (try (fst o HOLogic.dest_eq))
   694       |> head_of;
   751       |> head_of;
   695 
   752 
   700     val ctrs = maps (map #ctr) basic_ctr_specss;
   757     val ctrs = maps (map #ctr) basic_ctr_specss;
   701   in
   758   in
   702     if member (op =) discs head orelse
   759     if member (op =) discs head orelse
   703         is_some rhs_opt andalso
   760         is_some rhs_opt andalso
   704           member (op =) (filter (null o binder_types o fastype_of) ctrs) (the rhs_opt) then
   761           member (op =) (filter (null o binder_types o fastype_of) ctrs) (the rhs_opt) then
   705       dissect_coeqn_disc fun_names sequentials basic_ctr_specss eqn_pos NONE NONE prems concl
   762       dissect_coeqn_disc lthy fun_names sequentials basic_ctr_specss eqn_pos NONE NONE prems concl
   706         matchedsss
   763         matchedsss
   707       |>> single
   764       |>> single
   708     else if member (op =) sels head then
   765     else if member (op =) sels head then
   709       ([dissect_coeqn_sel fun_names basic_ctr_specss eqn_pos NONE NONE eqn0 of_spec_opt concl],
   766       ([dissect_coeqn_sel lthy fun_names basic_ctr_specss eqn_pos NONE NONE eqn0 of_spec_opt concl],
   710        matchedsss)
   767        matchedsss)
   711     else if is_Free head andalso member (op =) fun_names (fst (dest_Free head)) then
   768     else if is_some rhs_opt andalso
       
   769         is_Free head andalso member (op =) fun_names (fst (dest_Free head)) then
   712       if member (op =) ctrs (head_of (unfold_lets_splits (the rhs_opt))) then
   770       if member (op =) ctrs (head_of (unfold_lets_splits (the rhs_opt))) then
   713         dissect_coeqn_ctr fun_names sequentials basic_ctr_specss eqn_pos eqn0
   771         dissect_coeqn_ctr lthy fun_names sequentials basic_ctr_specss eqn_pos eqn0
   714           (if null prems then
   772           (if null prems then
   715              SOME (snd (HOLogic.dest_eq (HOLogic.dest_Trueprop (Logic.strip_assums_concl eqn0))))
   773              SOME (snd (HOLogic.dest_eq (HOLogic.dest_Trueprop (Logic.strip_assums_concl eqn0))))
   716            else
   774            else
   717              NONE)
   775              NONE)
   718           prems concl matchedsss
   776           prems concl matchedsss
   921     val eqns_data =
   979     val eqns_data =
   922       fold_map2 (dissect_coeqn lthy has_call fun_names sequentials basic_ctr_specss)
   980       fold_map2 (dissect_coeqn lthy has_call fun_names sequentials basic_ctr_specss)
   923         (tag_list 0 (map snd specs)) of_specs_opt []
   981         (tag_list 0 (map snd specs)) of_specs_opt []
   924       |> flat o fst;
   982       |> flat o fst;
   925 
   983 
       
   984     val _ =
       
   985       let
       
   986         val missing = fun_names
       
   987           |> filter (map (fn Disc x => #fun_name x | Sel x => #fun_name x) eqns_data
       
   988             |> not oo member (op =))
       
   989       in
       
   990         null missing
       
   991           orelse primcorec_error_eqns ("missing equations for function(s): " ^ commas missing) []
       
   992       end;
       
   993 
   926     val callssss =
   994     val callssss =
   927       map_filter (try (fn Sel x => x)) eqns_data
   995       map_filter (try (fn Sel x => x)) eqns_data
   928       |> partition_eq (op = o pairself #fun_name)
   996       |> partition_eq (op = o pairself #fun_name)
   929       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
   997       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
   930       |> map (flat o snd)
   998       |> map (flat o snd)
   944 
  1012 
   945     val disc_eqnss' = map_filter (try (fn Disc x => x)) eqns_data
  1013     val disc_eqnss' = map_filter (try (fn Disc x => x)) eqns_data
   946       |> partition_eq (op = o pairself #fun_name)
  1014       |> partition_eq (op = o pairself #fun_name)
   947       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
  1015       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
   948       |> map (sort (op < o pairself #ctr_no |> make_ord) o flat o snd);
  1016       |> map (sort (op < o pairself #ctr_no |> make_ord) o flat o snd);
       
  1017 
   949     val _ = disc_eqnss' |> map (fn x =>
  1018     val _ = disc_eqnss' |> map (fn x =>
   950       let val d = duplicates (op = o pairself #ctr_no) x in null d orelse
  1019       let val d = duplicates (op = o pairself #ctr_no) x in null d orelse
   951         primcorec_error_eqns "excess discriminator formula in definition"
  1020         (if forall (is_some o #ctr_rhs_opt) x then
   952           (maps (fn t => filter (curry (op =) (#ctr_no t) o #ctr_no) x) d |> map #user_eqn) end);
  1021           primcorec_error_eqns "multiple equations for constructor(s)"
       
  1022             (maps (fn t => filter (curry (op =) (#ctr_no t) o #ctr_no) x) d
       
  1023               |> map (the o #ctr_rhs_opt)) else
       
  1024           primcorec_error_eqns "excess discriminator formula in definition"
       
  1025             (maps (fn t => filter (curry (op =) (#ctr_no t) o #ctr_no) x) d |> map #user_eqn)) end);
   953 
  1026 
   954     val sel_eqnss = map_filter (try (fn Sel x => x)) eqns_data
  1027     val sel_eqnss = map_filter (try (fn Sel x => x)) eqns_data
   955       |> partition_eq (op = o pairself #fun_name)
  1028       |> partition_eq (op = o pairself #fun_name)
   956       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
  1029       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
   957       |> map (flat o snd);
  1030       |> map (flat o snd);
   979 
  1052 
   980     val excludess'' = map3 (fn tac_opt => fn sequential => map (fn (j, goal) =>
  1053     val excludess'' = map3 (fn tac_opt => fn sequential => map (fn (j, goal) =>
   981         (j, (Option.map (Goal.prove_sorry lthy [] [] goal #> Thm.close_derivation)
  1054         (j, (Option.map (Goal.prove_sorry lthy [] [] goal #> Thm.close_derivation)
   982            (exclude_tac tac_opt sequential j), goal))))
  1055            (exclude_tac tac_opt sequential j), goal))))
   983       tac_opts sequentials excludess';
  1056       tac_opts sequentials excludess';
       
  1057 
   984     val taut_thmss = map (map (apsnd (the o fst)) o filter (is_some o fst o snd)) excludess'';
  1058     val taut_thmss = map (map (apsnd (the o fst)) o filter (is_some o fst o snd)) excludess'';
   985     val (goal_idxss, exclude_goalss) = excludess''
  1059     val (goal_idxss, exclude_goalss) = excludess''
   986       |> map (map (apsnd (rpair [] o snd)) o filter (is_none o fst o snd))
  1060       |> map (map (apsnd (rpair [] o snd)) o filter (is_none o fst o snd))
   987       |> split_list o map split_list;
  1061       |> split_list o map split_list;
   988 
  1062