src/HOL/Tools/BNF/bnf_lfp_rec_sugar_more.ML
author blanchet
Wed, 19 Feb 2014 08:34:32 +0100
changeset 55574 4a940ebceef8
parent 55571 a6153343c44f
child 55575 a5e33e18fb5c
permissions -rw-r--r--
rewrote a small portion of code to avoid dependency on low-level constant
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
55571
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     1
(*  Title:      HOL/Tools/BNF/bnf_lfp_rec_sugar_more.ML
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     2
    Author:     Lorenz Panny, TU Muenchen
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     3
    Author:     Jasmin Blanchette, TU Muenchen
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     4
    Copyright   2013
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     5
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     6
More recursor sugar.
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     7
*)
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     8
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
     9
structure BNF_LFP_Rec_Sugar_More : sig end =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    10
struct
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    11
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    12
open BNF_Util
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    13
open BNF_Def
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    14
open BNF_FP_Util
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    15
open BNF_FP_Def_Sugar
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    16
open BNF_FP_N2M_Sugar
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    17
open BNF_LFP_Rec_Sugar
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    18
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    19
fun is_new_datatype ctxt s =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    20
  (case fp_sugar_of ctxt s of SOME {fp = Least_FP, ...} => true | _ => false);
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    21
55574
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    22
fun basic_lfp_sugar_of C fun_arg_Tsss ({T, fp_res_index, ctr_defs, ctr_sugar, co_iters = iters,
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    23
    co_iter_thmss = iter_thmss, ...} : fp_sugar) =
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    24
  {T = T, fp_res_index = fp_res_index, C = C, fun_arg_Tsss = fun_arg_Tsss, ctr_defs = ctr_defs,
55571
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    25
   ctr_sugar = ctr_sugar, recx = co_rec_of iters, rec_thms = co_rec_of iter_thmss};
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    26
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    27
fun get_basic_lfp_sugars bs arg_Ts get_indices callssss0 lthy0 =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    28
  let
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    29
    val ((missing_arg_Ts, perm0_kks,
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    30
          fp_sugars as {nested_bnfs, co_inducts = [induct_thm], ...} :: _, (lfp_sugar_thms, _)),
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    31
         lthy) =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    32
      nested_to_mutual_fps Least_FP bs arg_Ts get_indices callssss0 lthy0;
55574
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    33
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    34
    val Ts = map #T fp_sugars;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    35
    val Cs = map (body_type o fastype_of o co_rec_of o #co_iters) fp_sugars;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    36
    val Ts_Cs = Ts ~~ Cs;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    37
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    38
    fun zip_recT (T as Type (s, Ts)) =
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    39
        (case AList.lookup (op =) Ts_Cs T of
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    40
          SOME C => [T, C]
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    41
        | NONE => [Type (s, map (HOLogic.mk_tupleT o zip_recT) Ts)])
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    42
      | zip_recT T = [T];
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    43
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    44
    val ctrss = map (#ctrs o #ctr_sugar) fp_sugars;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    45
    val ctr_Tsss = map (map (binder_types o fastype_of)) ctrss;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    46
    val fun_arg_Tssss = map (map (map zip_recT)) ctr_Tsss;
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    47
55571
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    48
    val nested_map_idents = map (unfold_thms lthy @{thms id_def} o map_id0_of_bnf) nested_bnfs;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    49
    val nested_map_comps = map map_comp_of_bnf nested_bnfs;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    50
  in
55574
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    51
    (missing_arg_Ts, perm0_kks, map3 basic_lfp_sugar_of Cs fun_arg_Tssss fp_sugars,
4a940ebceef8 rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents: 55571
diff changeset
    52
     nested_map_idents, nested_map_comps, induct_thm, is_some lfp_sugar_thms, lthy)
55571
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    53
  end;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    54
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    55
exception NOT_A_MAP of term;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    56
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    57
fun ill_formed_rec_call ctxt t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    58
  error ("Ill-formed recursive call: " ^ quote (Syntax.string_of_term ctxt t));
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    59
fun invalid_map ctxt t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    60
  error ("Invalid map function in " ^ quote (Syntax.string_of_term ctxt t));
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    61
fun unexpected_rec_call ctxt t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    62
  error ("Unexpected recursive call: " ^ quote (Syntax.string_of_term ctxt t));
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    63
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    64
fun massage_nested_rec_call ctxt has_call raw_massage_fun bound_Ts y y' =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    65
  let
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    66
    fun check_no_call t = if has_call t then unexpected_rec_call ctxt t else ();
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    67
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    68
    val typof = curry fastype_of1 bound_Ts;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    69
    val build_map_fst = build_map ctxt (fst_const o fst);
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    70
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    71
    val yT = typof y;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    72
    val yU = typof y';
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    73
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    74
    fun y_of_y' () = build_map_fst (yU, yT) $ y';
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    75
    val elim_y = Term.map_aterms (fn t => if t = y then y_of_y' () else t);
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    76
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    77
    fun massage_mutual_fun U T t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    78
      (case t of
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    79
        Const (@{const_name comp}, _) $ t1 $ t2 =>
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    80
        mk_comp bound_Ts (tap check_no_call t1, massage_mutual_fun U T t2)
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    81
      | _ =>
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    82
        if has_call t then
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    83
          (case try HOLogic.dest_prodT U of
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    84
            SOME (U1, U2) => if U1 = T then raw_massage_fun T U2 t else invalid_map ctxt t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    85
          | NONE => invalid_map ctxt t)
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    86
        else
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    87
          mk_comp bound_Ts (t, build_map_fst (U, T)));
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    88
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    89
    fun massage_map (Type (_, Us)) (Type (s, Ts)) t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    90
        (case try (dest_map ctxt s) t of
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    91
          SOME (map0, fs) =>
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    92
          let
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    93
            val Type (_, ran_Ts) = range_type (typof t);
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    94
            val map' = mk_map (length fs) Us ran_Ts map0;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    95
            val fs' = map_flattened_map_args ctxt s (map3 massage_map_or_map_arg Us Ts) fs;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    96
          in
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    97
            Term.list_comb (map', fs')
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    98
          end
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
    99
        | NONE => raise NOT_A_MAP t)
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   100
      | massage_map _ _ t = raise NOT_A_MAP t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   101
    and massage_map_or_map_arg U T t =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   102
      if T = U then
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   103
        tap check_no_call t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   104
      else
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   105
        massage_map U T t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   106
        handle NOT_A_MAP _ => massage_mutual_fun U T t;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   107
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   108
    fun massage_call (t as t1 $ t2) =
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   109
        if has_call t then
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   110
          if t2 = y then
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   111
            massage_map yU yT (elim_y t1) $ y'
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   112
            handle NOT_A_MAP t' => invalid_map ctxt t'
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   113
          else
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   114
            let val (g, xs) = Term.strip_comb t2 in
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   115
              if g = y then
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   116
                if exists has_call xs then unexpected_rec_call ctxt t2
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   117
                else Term.list_comb (massage_call (mk_compN (length xs) bound_Ts (t1, y)), xs)
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   118
              else
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   119
                ill_formed_rec_call ctxt t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   120
            end
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   121
        else
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   122
          elim_y t
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   123
      | massage_call t = if t = y then y_of_y' () else ill_formed_rec_call ctxt t;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   124
  in
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   125
    massage_call
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   126
  end;
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   127
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   128
val _ = Theory.setup (register_lfp_rec_extension
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   129
  {is_new_datatype = is_new_datatype, get_basic_lfp_sugars = get_basic_lfp_sugars,
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   130
   massage_nested_rec_call = massage_nested_rec_call});
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   131
a6153343c44f prepare two-stage 'primrec' setup
blanchet
parents:
diff changeset
   132
end;