src/HOL/Tools/Lifting/lifting_setup.ML
author kuncar
Mon, 21 May 2012 16:36:48 +0200
changeset 48966 8c8a03765de7
parent 48958 c09326cedb41
child 48997 7aa35601ff65
permissions -rw-r--r--
quot_del attribute, it allows us to deregister quotient types
     1 (*  Title:      HOL/Tools/Lifting/lifting_setup.ML
     2     Author:     Ondrej Kuncar
     3 
     4 Setting up the lifting infrastructure.
     5 *)
     6 
     7 signature LIFTING_SETUP =
     8 sig
     9   exception SETUP_LIFTING_INFR of string
    10 
    11   val setup_by_quotient: bool -> thm -> thm option -> local_theory -> local_theory
    12 
    13   val setup_by_typedef_thm: bool -> thm -> local_theory -> local_theory
    14 end;
    15 
    16 structure Lifting_Setup: LIFTING_SETUP =
    17 struct
    18 
    19 open Lifting_Util
    20 
    21 infix 0 MRSL
    22 
    23 exception SETUP_LIFTING_INFR of string
    24 
    25 fun define_cr_rel rep_fun lthy =
    26   let
    27     val (qty, rty) = (dest_funT o fastype_of) rep_fun
    28     val rep_fun_graph = (HOLogic.eq_const rty) $ Bound 1 $ (rep_fun $ Bound 0)
    29     val def_term = Abs ("x", rty, Abs ("y", qty, rep_fun_graph));
    30     val qty_name = (fst o dest_Type) qty
    31     val cr_rel_name = Binding.prefix_name "cr_" (Binding.qualified_name qty_name)  
    32     val (fixed_def_term, lthy') = yield_singleton (Variable.importT_terms) def_term lthy
    33     val ((_, (_ , def_thm)), lthy'') =
    34       Local_Theory.define ((cr_rel_name, NoSyn), ((Thm.def_binding cr_rel_name, []), fixed_def_term)) lthy'
    35   in
    36     (def_thm, lthy'')
    37   end
    38 
    39 fun define_code_constr gen_code quot_thm lthy =
    40   let
    41     val abs = quot_thm_abs quot_thm
    42     val abs_background = Morphism.term (Local_Theory.target_morphism lthy) abs
    43   in
    44     if gen_code andalso is_Const abs_background then
    45       let
    46         val (const_name, typ) = dest_Const abs_background
    47         val fake_term = Logic.mk_type typ
    48         val (fixed_fake_term, lthy') = yield_singleton(Variable.importT_terms) fake_term lthy
    49         val fixed_type = Logic.dest_type fixed_fake_term
    50       in  
    51          Local_Theory.background_theory(Code.add_datatype [(const_name, fixed_type)]) lthy'
    52       end
    53     else
    54       lthy
    55   end
    56 
    57 fun define_abs_type gen_code quot_thm lthy =
    58   if gen_code andalso Lifting_Def.can_generate_code_cert quot_thm then
    59     let
    60       val abs_type_thm = quot_thm RS @{thm Quotient_abs_rep}
    61       val add_abstype_attribute = 
    62           Thm.declaration_attribute (fn thm => Context.mapping (Code.add_abstype thm) I)
    63         val add_abstype_attrib = Attrib.internal (K add_abstype_attribute);
    64     in
    65       lthy
    66         |> (snd oo Local_Theory.note) ((Binding.empty, [add_abstype_attrib]), [abs_type_thm])
    67     end
    68   else
    69     lthy
    70 
    71 fun quot_thm_sanity_check ctxt quot_thm =
    72   let
    73     val ((_, [quot_thm_fixed]), ctxt') = Variable.importT [quot_thm] ctxt 
    74     val (rty, qty) = quot_thm_rty_qty quot_thm_fixed
    75     val rty_tfreesT = Term.add_tfree_namesT rty []
    76     val qty_tfreesT = Term.add_tfree_namesT qty []
    77     val extra_rty_tfrees =
    78       case subtract (op =) qty_tfreesT rty_tfreesT of
    79         [] => []
    80       | extras => [Pretty.block ([Pretty.str "Extra variables in the raw type:",
    81                                  Pretty.brk 1] @ 
    82                                  ((Pretty.commas o map (Pretty.str o quote)) extras) @
    83                                  [Pretty.str "."])]
    84     val not_type_constr = 
    85       case qty of
    86          Type _ => []
    87          | _ => [Pretty.block [Pretty.str "The quotient type ",
    88                                 Pretty.quote (Syntax.pretty_typ ctxt' qty),
    89                                 Pretty.brk 1,
    90                                 Pretty.str "is not a type constructor."]]
    91     val errs = extra_rty_tfrees @ not_type_constr
    92   in
    93     if null errs then () else error (cat_lines (["Sanity check of the quotient theorem failed:",""] 
    94                                                 @ (map Pretty.string_of errs)))
    95   end
    96 
    97 fun setup_lifting_infr gen_code quot_thm maybe_reflp_thm lthy =
    98   let
    99     val _ = quot_thm_sanity_check lthy quot_thm
   100     val (_, qtyp) = quot_thm_rty_qty quot_thm
   101     val qty_full_name = (fst o dest_Type) qtyp
   102     val quotients = { quot_thm = quot_thm }
   103     fun quot_info phi = Lifting_Info.transform_quotients phi quotients
   104     val lthy' = case maybe_reflp_thm of
   105       SOME reflp_thm => lthy
   106         |> (snd oo Local_Theory.note) ((Binding.empty, [Lifting_Info.add_reflp_preserve_rule_attrib]),
   107               [reflp_thm])
   108         |> define_code_constr gen_code quot_thm
   109       | NONE => lthy
   110         |> define_abs_type gen_code quot_thm
   111   in
   112     lthy'
   113       |> Local_Theory.declaration {syntax = false, pervasive = true}
   114         (fn phi => Lifting_Info.update_quotients qty_full_name (quot_info phi))
   115   end
   116 
   117 (*
   118   Sets up the Lifting package by a quotient theorem.
   119 
   120   gen_code - flag if an abstract type given by quot_thm should be registred 
   121     as an abstract type in the code generator
   122   quot_thm - a quotient theorem (Quotient R Abs Rep T)
   123   maybe_reflp_thm - a theorem saying that a relation from quot_thm is reflexive
   124     (in the form "reflp R")
   125 *)
   126 
   127 fun setup_by_quotient gen_code quot_thm maybe_reflp_thm lthy =
   128   let
   129     val transfer_attr = Attrib.internal (K Transfer.transfer_add)
   130     val (_, qty) = quot_thm_rty_qty quot_thm
   131     val induct_attr = Attrib.internal (K (Induct.induct_type (fst (dest_Type qty))))
   132     val qty_name = (Binding.name o Long_Name.base_name o fst o dest_Type) qty
   133     fun qualify suffix = Binding.qualified true suffix qty_name
   134     val lthy' = case maybe_reflp_thm of
   135       SOME reflp_thm => lthy
   136         |> (snd oo Local_Theory.note) ((qualify "bi_total", [transfer_attr]), 
   137           [[quot_thm, reflp_thm] MRSL @{thm Quotient_bi_total}])
   138         |> (snd oo Local_Theory.note) ((qualify "id_abs_transfer", [transfer_attr]), 
   139           [[quot_thm, reflp_thm] MRSL @{thm Quotient_id_abs_transfer}])
   140         |> (snd oo Local_Theory.note) ((qualify "abs_induct", [induct_attr]),
   141           [[quot_thm, reflp_thm] MRSL @{thm Quotient_total_abs_induct}])
   142         |> (snd oo Local_Theory.note) ((qualify "abs_eq_iff", []),
   143           [[quot_thm, reflp_thm] MRSL @{thm Quotient_total_abs_eq_iff}])
   144       | NONE => lthy
   145         |> (snd oo Local_Theory.note) ((qualify "All_transfer", [transfer_attr]), 
   146           [quot_thm RS @{thm Quotient_All_transfer}])
   147         |> (snd oo Local_Theory.note) ((qualify "Ex_transfer", [transfer_attr]), 
   148           [quot_thm RS @{thm Quotient_Ex_transfer}])
   149         |> (snd oo Local_Theory.note) ((qualify "forall_transfer", [transfer_attr]), 
   150           [quot_thm RS @{thm Quotient_forall_transfer}])
   151         |> (snd oo Local_Theory.note) ((qualify "abs_induct", [induct_attr]),
   152           [quot_thm RS @{thm Quotient_abs_induct}])
   153   in
   154     lthy'
   155       |> (snd oo Local_Theory.note) ((qualify "right_unique", [transfer_attr]), 
   156         [quot_thm RS @{thm Quotient_right_unique}])
   157       |> (snd oo Local_Theory.note) ((qualify "right_total", [transfer_attr]), 
   158         [quot_thm RS @{thm Quotient_right_total}])
   159       |> (snd oo Local_Theory.note) ((qualify "rel_eq_transfer", [transfer_attr]), 
   160         [quot_thm RS @{thm Quotient_rel_eq_transfer}])
   161       |> setup_lifting_infr gen_code quot_thm maybe_reflp_thm
   162   end
   163 
   164 (*
   165   Sets up the Lifting package by a typedef theorem.
   166 
   167   gen_code - flag if an abstract type given by typedef_thm should be registred 
   168     as an abstract type in the code generator
   169   typedef_thm - a typedef theorem (type_definition Rep Abs S)
   170 *)
   171 
   172 fun setup_by_typedef_thm gen_code typedef_thm lthy =
   173   let
   174     val transfer_attr = Attrib.internal (K Transfer.transfer_add)
   175     val (_ $ rep_fun $ _ $ typedef_set) = (HOLogic.dest_Trueprop o prop_of) typedef_thm
   176     val (T_def, lthy') = define_cr_rel rep_fun lthy
   177 
   178     val quot_thm = case typedef_set of
   179       Const ("Orderings.top_class.top", _) => 
   180         [typedef_thm, T_def] MRSL @{thm UNIV_typedef_to_Quotient}
   181       | Const (@{const_name "Collect"}, _) $ Abs (_, _, _) => 
   182         [typedef_thm, T_def] MRSL @{thm open_typedef_to_Quotient}
   183       | _ => 
   184         [typedef_thm, T_def] MRSL @{thm typedef_to_Quotient}
   185 
   186     val (_, qty) = quot_thm_rty_qty quot_thm
   187     val qty_name = (Binding.name o Long_Name.base_name o fst o dest_Type) qty
   188     fun qualify suffix = Binding.qualified true suffix qty_name
   189     val simplify = Raw_Simplifier.rewrite_rule [mk_meta_eq @{thm mem_Collect_eq}]
   190 
   191     val (maybe_reflp_thm, lthy'') = case typedef_set of
   192       Const ("Orderings.top_class.top", _) => 
   193         let
   194           val equivp_thm = typedef_thm RS @{thm UNIV_typedef_to_equivp}
   195           val reflp_thm = equivp_thm RS @{thm equivp_reflp2}
   196         in
   197           lthy'
   198             |> (snd oo Local_Theory.note) ((qualify "bi_total", [transfer_attr]), 
   199               [[quot_thm, reflp_thm] MRSL @{thm Quotient_bi_total}])
   200             |> (snd oo Local_Theory.note) ((qualify "id_abs_transfer", [transfer_attr]), 
   201               [[quot_thm, reflp_thm] MRSL @{thm Quotient_id_abs_transfer}])
   202             |> pair (SOME reflp_thm)
   203         end
   204       | _ => lthy'
   205         |> (snd oo Local_Theory.note) ((qualify "All_transfer", [transfer_attr]), 
   206           [[typedef_thm, T_def] MRSL @{thm typedef_All_transfer}])
   207         |> (snd oo Local_Theory.note) ((qualify "Ex_transfer", [transfer_attr]), 
   208           [[typedef_thm, T_def] MRSL @{thm typedef_Ex_transfer}])
   209         |> (snd oo Local_Theory.note) ((qualify "forall_transfer", [transfer_attr]), 
   210           [simplify ([typedef_thm, T_def] MRSL @{thm typedef_forall_transfer})])
   211         |> pair NONE
   212   in
   213     lthy''
   214       |> (snd oo Local_Theory.note) ((Binding.prefix_name "Quotient_" qty_name, []), 
   215         [quot_thm])
   216       |> (snd oo Local_Theory.note) ((qualify "bi_unique", [transfer_attr]), 
   217         [[typedef_thm, T_def] MRSL @{thm typedef_bi_unique}])
   218       |> (snd oo Local_Theory.note) ((qualify "rep_transfer", [transfer_attr]), 
   219         [[typedef_thm, T_def] MRSL @{thm typedef_rep_transfer}])
   220       |> (snd oo Local_Theory.note) ((qualify "right_unique", [transfer_attr]), 
   221         [[quot_thm] MRSL @{thm Quotient_right_unique}])
   222       |> (snd oo Local_Theory.note) ((qualify "right_total", [transfer_attr]), 
   223         [[quot_thm] MRSL @{thm Quotient_right_total}])
   224       |> setup_lifting_infr gen_code quot_thm maybe_reflp_thm
   225   end
   226 
   227 fun setup_lifting_cmd gen_code xthm opt_reflp_xthm lthy =
   228   let 
   229     val input_thm = singleton (Attrib.eval_thms lthy) xthm
   230     val input_term = (HOLogic.dest_Trueprop o prop_of) input_thm
   231       handle TERM _ => error "Unsupported type of a theorem. Only Quotient or type_definition are supported."
   232 
   233     fun sanity_check_reflp_thm reflp_thm = 
   234       let
   235         val reflp_tm = (HOLogic.dest_Trueprop o prop_of) reflp_thm
   236           handle TERM _ => error "Invalid form of the reflexivity theorem. Use \"reflp R\"."
   237       in
   238         case reflp_tm of
   239           Const (@{const_name reflp}, _) $ _ => ()
   240           | _ => error "Invalid form of the reflexivity theorem. Use \"reflp R\"."
   241       end
   242 
   243     fun setup_quotient () = 
   244       case opt_reflp_xthm of
   245         SOME reflp_xthm => 
   246           let
   247             val reflp_thm = singleton (Attrib.eval_thms lthy) reflp_xthm
   248             val _ = sanity_check_reflp_thm reflp_thm
   249           in
   250             setup_by_quotient gen_code input_thm (SOME reflp_thm) lthy
   251           end
   252         | NONE => setup_by_quotient gen_code input_thm NONE lthy
   253 
   254     fun setup_typedef () = 
   255       case opt_reflp_xthm of
   256         SOME _ => error "The reflexivity theorem cannot be specified if the type_definition theorem is used."
   257         | NONE => setup_by_typedef_thm gen_code input_thm lthy
   258   in
   259     case input_term of
   260       (Const (@{const_name Quotient}, _) $ _ $ _ $ _ $ _) => setup_quotient ()
   261       | (Const (@{const_name type_definition}, _) $ _ $ _ $ _) => setup_typedef ()
   262       | _ => error "Unsupported type of a theorem. Only Quotient or type_definition are supported."
   263   end
   264 
   265 val opt_gen_code =
   266   Scan.optional (@{keyword "("} |-- Parse.!!! ((Parse.reserved "no_code" >> K false) --| @{keyword ")"})) true
   267 
   268 val _ = 
   269   Outer_Syntax.local_theory @{command_spec "setup_lifting"}
   270     "Setup lifting infrastructure" 
   271       (opt_gen_code -- Parse_Spec.xthm -- Scan.option Parse_Spec.xthm >> 
   272         (fn ((gen_code, xthm), opt_reflp_xthm) => setup_lifting_cmd gen_code xthm opt_reflp_xthm))
   273 end;