src/HOL/Tools/BNF/bnf_gfp_rec_sugar.ML
changeset 59599 6a7e11fc6ee2
parent 59598 c9d304d6ae98
child 59600 1716da11a11c
equal deleted inserted replaced
59598:c9d304d6ae98 59599:6a7e11fc6ee2
    82 val selN = "sel";
    82 val selN = "sel";
    83 
    83 
    84 val nitpicksimp_attrs = @{attributes [nitpick_simp]};
    84 val nitpicksimp_attrs = @{attributes [nitpick_simp]};
    85 val simp_attrs = @{attributes [simp]};
    85 val simp_attrs = @{attributes [simp]};
    86 
    86 
       
    87 fun extra_variable ctxt ts var =
       
    88   error_at ctxt ts ("Extra variable " ^ quote (Syntax.string_of_term ctxt var));
    87 fun not_codatatype ctxt T =
    89 fun not_codatatype ctxt T =
    88   error ("Not a codatatype: " ^ Syntax.string_of_typ ctxt T);
    90   error ("Not a codatatype: " ^ Syntax.string_of_typ ctxt T);
    89 fun ill_formed_corec_call ctxt t =
    91 fun ill_formed_corec_call ctxt t =
    90   error ("Ill-formed corecursive call " ^ quote (Syntax.string_of_term ctxt t));
    92   error ("Ill-formed corecursive call " ^ quote (Syntax.string_of_term ctxt t));
    91 fun invalid_map ctxt t =
    93 fun invalid_map ctxt t =
   581   Sel of coeqn_data_sel;
   583   Sel of coeqn_data_sel;
   582 
   584 
   583 fun is_free_in frees (Free (v, _)) = member (op =) frees v
   585 fun is_free_in frees (Free (v, _)) = member (op =) frees v
   584   | is_free_in _ _ = false;
   586   | is_free_in _ _ = false;
   585 
   587 
   586 fun check_extra_variables ctxt vars names eqn =
   588 fun add_extra_frees ctxt frees names =
   587   let val b = fold_aterms (fn x as Free (v, _) =>
   589   fold_aterms (fn x as Free (v, _) =>
   588     if (not (member (op =) vars x) andalso
   590     (not (member (op =) frees x) andalso not (member (op =) names v) andalso
   589       not (member (op =) names v) andalso
   591      not (Variable.is_fixed ctxt v) andalso v <> Name.uu_)
   590       v <> Name.uu_ andalso
   592     ? cons x | _ => I);
   591       not (Variable.is_fixed ctxt v)) then cons x else I | _ => I) eqn []
   593 
   592   in
   594 fun check_extra_frees ctxt frees names t =
   593     null b orelse error_at ctxt [eqn]
   595   let val bads = add_extra_frees ctxt frees names t [] in
   594       ("Extra variable " ^ quote (Syntax.string_of_term ctxt (hd b)))
   596     null bads orelse extra_variable ctxt [t] (hd bads)
   595   end;
   597   end;
   596 
   598 
   597 fun dissect_coeqn_disc ctxt fun_names sequentials
   599 fun dissect_coeqn_disc ctxt fun_names sequentials
   598     (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos ctr_rhs_opt code_rhs_opt prems0
   600     (basic_ctr_specss : basic_corec_ctr_spec list list) eqn_pos ctr_rhs_opt code_rhs_opt prems0
   599     concl matchedsss =
   601     concl matchedsss =
   663     val user_eqn =
   665     val user_eqn =
   664       (actual_prems, concl)
   666       (actual_prems, concl)
   665       |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args)
   667       |>> map HOLogic.mk_Trueprop ||> HOLogic.mk_Trueprop o abstract (List.rev fun_args)
   666       |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies;
   668       |> curry Logic.list_all (map dest_Free fun_args) o Logic.list_implies;
   667 
   669 
   668     val _ = check_extra_variables ctxt fun_args fun_names user_eqn;
   670     val _ = check_extra_frees ctxt fun_args fun_names user_eqn;
   669   in
   671   in
   670     (Disc {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, ctr_no = ctr_no,
   672     (Disc {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, ctr_no = ctr_no,
   671        disc = disc, prems = actual_prems, auto_gen = catch_all, ctr_rhs_opt = ctr_rhs_opt,
   673        disc = disc, prems = actual_prems, auto_gen = catch_all, ctr_rhs_opt = ctr_rhs_opt,
   672        code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, user_eqn = user_eqn},
   674        code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos, user_eqn = user_eqn},
   673      matchedsss')
   675      matchedsss')
   694         SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs)
   696         SOME of_spec => the (find_first (curry (op =) of_spec o #ctr) basic_ctr_specs)
   695       | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single
   697       | NONE => filter (exists (curry (op =) sel) o #sels) basic_ctr_specs |> the_single
   696           handle List.Empty => error_at ctxt [eqn] "Ambiguous selector (without \"of\")");
   698           handle List.Empty => error_at ctxt [eqn] "Ambiguous selector (without \"of\")");
   697     val user_eqn = drop_all eqn0;
   699     val user_eqn = drop_all eqn0;
   698 
   700 
   699     val _ = check_extra_variables ctxt fun_args fun_names user_eqn;
   701     val _ = check_extra_frees ctxt fun_args fun_names user_eqn;
   700   in
   702   in
   701     Sel {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, sel = sel,
   703     Sel {fun_name = fun_name, fun_T = fun_T, fun_args = fun_args, ctr = ctr, sel = sel,
   702       rhs_term = rhs, ctr_rhs_opt = ctr_rhs_opt, code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos,
   704       rhs_term = rhs, ctr_rhs_opt = ctr_rhs_opt, code_rhs_opt = code_rhs_opt, eqn_pos = eqn_pos,
   703       user_eqn = user_eqn}
   705       user_eqn = user_eqn}
   704   end;
   706   end;
   707     eqn_pos eqn0 code_rhs_opt prems concl matchedsss =
   709     eqn_pos eqn0 code_rhs_opt prems concl matchedsss =
   708   let
   710   let
   709     val (lhs, rhs) = HOLogic.dest_eq concl;
   711     val (lhs, rhs) = HOLogic.dest_eq concl;
   710     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   712     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   711 
   713 
   712     val _ = check_extra_variables ctxt fun_args fun_names (drop_all eqn0);
   714     val _ = check_extra_frees ctxt fun_args fun_names (drop_all eqn0);
   713 
   715 
   714     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name);
   716     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name);
   715     val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs);
   717     val (ctr, ctr_args) = strip_comb (unfold_lets_splits rhs);
   716     val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs)
   718     val {disc, sels, ...} = the (find_first (curry (op =) ctr o #ctr) basic_ctr_specs)
   717       handle Option.Option => error_at ctxt [ctr] "Not a constructor";
   719       handle Option.Option => error_at ctxt [ctr] "Not a constructor";
   739 fun dissect_coeqn_code ctxt has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss =
   741 fun dissect_coeqn_code ctxt has_call fun_names basic_ctr_specss eqn_pos eqn0 concl matchedsss =
   740   let
   742   let
   741     val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs ctxt has_call []);
   743     val (lhs, (rhs', rhs)) = HOLogic.dest_eq concl ||> `(expand_corec_code_rhs ctxt has_call []);
   742     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   744     val (fun_name, fun_args) = strip_comb lhs |>> fst o dest_Free;
   743 
   745 
   744     val _ = check_extra_variables ctxt fun_args fun_names concl;
   746     val _ = check_extra_frees ctxt fun_args fun_names concl;
   745 
   747 
   746     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name);
   748     val basic_ctr_specs = the (AList.lookup (op =) (fun_names ~~ basic_ctr_specss) fun_name);
   747 
   749 
   748     val cond_ctrs = fold_rev_corec_code_rhs ctxt (fn cs => fn ctr => fn _ =>
   750     val cond_ctrs = fold_rev_corec_code_rhs ctxt (fn cs => fn ctr => fn _ =>
   749         if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs)
   751         if member (op = o apsnd #ctr) basic_ctr_specs ctr then cons (ctr, cs)
   913           if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, @{term False})
   915           if range_type T = HOLogic.boolT then Abs (Name.uu_, domain_type T, @{term False})
   914           else Const (@{const_name undefined}, T))
   916           else Const (@{const_name undefined}, T))
   915       |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss
   917       |> fold2 (fold o build_corec_arg_disc) ctr_specss disc_eqnss
   916       |> fold2 (fold o build_corec_args_sel ctxt has_call) sel_eqnss ctr_specss;
   918       |> fold2 (fold o build_corec_args_sel ctxt has_call) sel_eqnss ctr_specss;
   917 
   919 
       
   920     val bad = fold (add_extra_frees ctxt [] []) corec_args [];
       
   921     val _ = null bad orelse
       
   922       (if exists has_call corec_args then nonprimitive_corec ctxt []
       
   923        else extra_variable ctxt [] (hd bad));
       
   924 
   918     fun currys [] t = t
   925     fun currys [] t = t
   919       | currys Ts t = t $ mk_tuple1_balanced (List.rev Ts) (map Bound (length Ts - 1 downto 0))
   926       | currys Ts t = t $ mk_tuple1_balanced (List.rev Ts) (map Bound (length Ts - 1 downto 0))
   920           |> fold_rev (Term.abs o pair Name.uu) Ts;
   927           |> fold_rev (Term.abs o pair Name.uu) Ts;
   921 
   928 
   922     val excludess' =
   929     val excludess' =
  1052               |> map (the o #ctr_rhs_opt))
  1059               |> map (the o #ctr_rhs_opt))
  1053              "Multiple equations for same constructor"
  1060              "Multiple equations for same constructor"
  1054          else
  1061          else
  1055            error_at lthy
  1062            error_at lthy
  1056              (maps (fn t => filter (curry (op =) (#ctr_no t) o #ctr_no) x) d |> map #user_eqn)
  1063              (maps (fn t => filter (curry (op =) (#ctr_no t) o #ctr_no) x) d |> map #user_eqn)
  1057              "Excess discriminator formula in definition")
  1064              "Extra discriminator formula in definition")
  1058       end);
  1065       end);
  1059 
  1066 
  1060     val sel_eqnss = map_filter (try (fn Sel x => x)) eqns_data
  1067     val sel_eqnss = map_filter (try (fn Sel x => x)) eqns_data
  1061       |> partition_eq (op = o apply2 #fun_name)
  1068       |> partition_eq (op = o apply2 #fun_name)
  1062       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names
  1069       |> fst o finds (fn (x, ({fun_name, ...} :: _)) => x = fun_name) fun_names