src/HOL/Tools/choice_specification.ML
author wenzelm
Sat Mar 22 18:19:57 2014 +0100 (2014-03-22)
changeset 56254 a2dd9200854d
parent 54742 7a86358a3c0b
child 56270 ce9c7a527c4b
permissions -rw-r--r--
more antiquotations;
     1 (*  Title:      HOL/Tools/choice_specification.ML
     2     Author:     Sebastian Skalberg, TU Muenchen
     3 
     4 Package for defining constants by specification.
     5 *)
     6 
     7 signature CHOICE_SPECIFICATION =
     8 sig
     9   val close_form : term -> term
    10   val add_specification: string option -> (bstring * xstring * bool) list ->
    11     theory * thm -> theory * thm
    12 end
    13 
    14 structure Choice_Specification: CHOICE_SPECIFICATION =
    15 struct
    16 
    17 (* actual code *)
    18 
    19 fun close_form t =
    20     fold_rev (fn (s, T) => fn t => HOLogic.mk_all (s, T, t))
    21              (map dest_Free (Misc_Legacy.term_frees t)) t
    22 
    23 fun add_final overloaded (c, T) thy =
    24   let
    25     val ctxt = Syntax.init_pretty_global thy;
    26     val _ = Theory.check_overloading ctxt overloaded (c, T);
    27   in Theory.add_deps ctxt "" (c, T) [] thy end;
    28 
    29 local
    30     fun mk_definitional [] arg = arg
    31       | mk_definitional ((thname,cname,covld)::cos) (thy,thm) =
    32         case HOLogic.dest_Trueprop (concl_of thm) of
    33             Const(@{const_name Ex},_) $ P =>
    34             let
    35                 val ctype = domain_type (type_of P)
    36                 val cname_full = Sign.intern_const thy cname
    37                 val cdefname = if thname = ""
    38                                then Thm.def_name (Long_Name.base_name cname)
    39                                else thname
    40                 val def_eq = Logic.mk_equals (Const(cname_full,ctype),
    41                                               HOLogic.choice_const ctype $  P)
    42                 val (thms, thy') = Global_Theory.add_defs covld [((Binding.name cdefname, def_eq),[])] thy
    43                 val thm' = [thm,hd thms] MRS @{thm exE_some}
    44             in
    45                 mk_definitional cos (thy',thm')
    46             end
    47           | _ => raise THM ("Internal error: Bad specification theorem",0,[thm])
    48 
    49     fun mk_axiomatic axname cos arg =
    50         let
    51             fun process [] (thy,tm) =
    52                 let
    53                     val (thm, thy') =
    54                       Specification.axiom ((Binding.name axname, []), HOLogic.mk_Trueprop tm) thy
    55                 in
    56                     (thy', Drule.export_without_context thm)
    57                 end
    58               | process ((thname,cname,covld)::cos) (thy,tm) =
    59                 case tm of
    60                     Const(@{const_name Ex},_) $ P =>
    61                     let
    62                         val ctype = domain_type (type_of P)
    63                         val cname_full = Sign.intern_const thy cname
    64                         val cdefname = if thname = ""
    65                                        then Thm.def_name (Long_Name.base_name cname)
    66                                        else thname
    67                         val thy' = add_final covld (cname_full,ctype) thy
    68                         val co = Const (cname_full,ctype)
    69                         val tm' = case P of
    70                                       Abs(_, _, bodt) => subst_bound (co, bodt)
    71                                     | _ => P $ co
    72                     in
    73                         process cos (thy',tm')
    74                     end
    75                   | _ => raise TERM ("Internal error: Bad specification theorem",[tm])
    76         in
    77             process cos arg
    78         end
    79 
    80 in
    81 fun proc_exprop axiomatic cos arg =
    82     case axiomatic of
    83         SOME axname => mk_axiomatic axname cos (apsnd (HOLogic.dest_Trueprop o concl_of) arg)
    84       | NONE => mk_definitional cos arg
    85 end
    86 
    87 fun add_specification axiomatic cos =
    88     proc_exprop axiomatic cos
    89     #> apsnd Drule.export_without_context
    90 
    91 
    92 (* Collect all intances of constants in term *)
    93 
    94 fun collect_consts (        t $ u,tms) = collect_consts (u,collect_consts (t,tms))
    95   | collect_consts (   Abs(_,_,t),tms) = collect_consts (t,tms)
    96   | collect_consts (tm as Const _,tms) = insert (op aconv) tm tms
    97   | collect_consts (            _,tms) = tms
    98 
    99 (* Complementing Type.varify_global... *)
   100 
   101 fun unvarify_global t fmap =
   102     let
   103         val fmap' = map Library.swap fmap
   104         fun unthaw (f as (a, S)) =
   105             (case AList.lookup (op =) fmap' a of
   106                  NONE => TVar f
   107                | SOME (b, _) => TFree (b, S))
   108     in
   109         map_types (map_type_tvar unthaw) t
   110     end
   111 
   112 (* The syntactic meddling needed to setup add_specification for work *)
   113 
   114 fun process_spec axiomatic cos alt_props thy =
   115     let
   116         val ctxt = Proof_Context.init_global thy
   117 
   118         fun zip3 [] [] [] = []
   119           | zip3 (x::xs) (y::ys) (z::zs) = (x,y,z)::zip3 xs ys zs
   120           | zip3 _ _ _ = error "Choice_Specification.process_spec internal error"
   121 
   122         fun myfoldr f [x] = x
   123           | myfoldr f (x::xs) = f (x,myfoldr f xs)
   124           | myfoldr f [] = error "Choice_Specification.process_spec internal error"
   125 
   126         val rew_imps = alt_props |>
   127           map (Object_Logic.atomize ctxt o Thm.cterm_of thy o Syntax.read_prop_global thy o snd)
   128         val props' = rew_imps |>
   129           map (HOLogic.dest_Trueprop o term_of o snd o Thm.dest_equals o cprop_of)
   130 
   131         fun proc_single prop =
   132             let
   133                 val frees = Misc_Legacy.term_frees prop
   134                 val _ = forall (fn v => Sign.of_sort thy (type_of v,@{sort type})) frees
   135                   orelse error "Specificaton: Only free variables of sort 'type' allowed"
   136                 val prop_closed = close_form prop
   137             in
   138                 (prop_closed,frees)
   139             end
   140 
   141         val props'' = map proc_single props'
   142         val frees = map snd props''
   143         val prop  = myfoldr HOLogic.mk_conj (map fst props'')
   144         val cprop = cterm_of thy (HOLogic.mk_Trueprop prop)
   145 
   146         val (vmap, prop_thawed) = Type.varify_global [] prop
   147         val thawed_prop_consts = collect_consts (prop_thawed,[])
   148         val (altcos,overloaded) = Library.split_list cos
   149         val (names,sconsts) = Library.split_list altcos
   150         val consts = map (Syntax.read_term_global thy) sconsts
   151         val _ = not (Library.exists (not o Term.is_Const) consts)
   152           orelse error "Specification: Non-constant found as parameter"
   153 
   154         fun proc_const c =
   155             let
   156                 val (_, c') = Type.varify_global [] c
   157                 val (cname,ctyp) = dest_Const c'
   158             in
   159                 case filter (fn t => let val (name,typ) = dest_Const t
   160                                      in name = cname andalso Sign.typ_equiv thy (typ, ctyp)
   161                                      end) thawed_prop_consts of
   162                     [] => error ("Specification: No suitable instances of constant \"" ^ Syntax.string_of_term_global thy c ^ "\" found")
   163                   | [cf] => unvarify_global cf vmap
   164                   | _ => error ("Specification: Several variations of \"" ^ Syntax.string_of_term_global thy c ^ "\" found (try applying explicit type constraints)")
   165             end
   166         val proc_consts = map proc_const consts
   167         fun mk_exist c prop =
   168             let
   169                 val T = type_of c
   170                 val cname = Long_Name.base_name (fst (dest_Const c))
   171                 val vname = if Symbol_Pos.is_identifier cname
   172                             then cname
   173                             else "x"
   174             in
   175                 HOLogic.exists_const T $ Abs(vname,T,Term.abstract_over (c,prop))
   176             end
   177         val ex_prop = fold_rev mk_exist proc_consts prop
   178         val cnames = map (fst o dest_Const) proc_consts
   179         fun post_process (arg as (thy,thm)) =
   180             let
   181                 fun inst_all thy v thm =
   182                     let
   183                         val cv = cterm_of thy v
   184                         val cT = ctyp_of_term cv
   185                         val spec' = instantiate' [SOME cT] [NONE,SOME cv] spec
   186                     in
   187                         thm RS spec'
   188                     end
   189                 fun remove_alls frees thm =
   190                     fold (inst_all (Thm.theory_of_thm thm)) frees thm
   191                 fun process_single ((name,atts),rew_imp,frees) args =
   192                     let
   193                         fun undo_imps thm =
   194                             Thm.equal_elim (Thm.symmetric rew_imp) thm
   195 
   196                         fun add_final (thm, thy) =
   197                             if name = ""
   198                             then (thm, thy)
   199                             else (writeln ("  " ^ name ^ ": " ^ Display.string_of_thm_global thy thm);
   200                                   Global_Theory.store_thm (Binding.name name, thm) thy)
   201                     in
   202                         swap args
   203                              |> apfst (remove_alls frees)
   204                              |> apfst undo_imps
   205                              |> apfst Drule.export_without_context
   206                              |-> Thm.theory_attributes
   207                                 (map (Attrib.attribute_cmd_global thy)
   208                                   (@{attributes [nitpick_choice_spec]} @ atts))
   209                              |> add_final
   210                              |> swap
   211                     end
   212 
   213                 fun process_all [proc_arg] args =
   214                     process_single proc_arg args
   215                   | process_all (proc_arg::rest) (thy,thm) =
   216                     let
   217                         val single_th = thm RS conjunct1
   218                         val rest_th   = thm RS conjunct2
   219                         val (thy',_)  = process_single proc_arg (thy,single_th)
   220                     in
   221                         process_all rest (thy',rest_th)
   222                     end
   223                   | process_all [] _ = error "Choice_Specification.process_spec internal error"
   224                 val alt_names = map fst alt_props
   225                 val _ = if exists (fn(name,_) => not (name = "")) alt_names
   226                         then writeln "specification"
   227                         else ()
   228             in
   229                 arg |> apsnd Thm.unvarify_global
   230                     |> process_all (zip3 alt_names rew_imps frees)
   231             end
   232 
   233       fun after_qed [[thm]] = Proof_Context.background_theory (fn thy =>
   234         #1 (post_process (add_specification axiomatic (zip3 names cnames overloaded) (thy, thm))));
   235     in
   236       thy
   237       |> Proof_Context.init_global
   238       |> Variable.declare_term ex_prop
   239       |> Proof.theorem NONE after_qed [[(HOLogic.mk_Trueprop ex_prop, [])]]
   240     end;
   241 
   242 
   243 (* outer syntax *)
   244 
   245 val opt_name = Scan.optional (Parse.name --| @{keyword ":"}) ""
   246 val opt_overloaded = Parse.opt_keyword "overloaded"
   247 
   248 val _ =
   249   Outer_Syntax.command @{command_spec "specification"} "define constants by specification"
   250     (@{keyword "("} |-- Scan.repeat1 (opt_name -- Parse.term -- opt_overloaded) --| @{keyword ")"} --
   251       Scan.repeat1 ((Parse_Spec.opt_thm_name ":" >> apfst Binding.name_of) -- Parse.prop)
   252       >> (fn (cos, alt_props) => Toplevel.print o
   253           (Toplevel.theory_to_proof (process_spec NONE cos alt_props))))
   254 
   255 val _ =
   256   Outer_Syntax.command @{command_spec "ax_specification"} "define constants by specification"
   257     (Parse.name --
   258       (@{keyword "("} |-- Scan.repeat1 (opt_name -- Parse.term -- opt_overloaded) --| @{keyword ")"} --
   259         Scan.repeat1 ((Parse_Spec.opt_thm_name ":" >> apfst Binding.name_of) -- Parse.prop))
   260       >> (fn (axname, (cos, alt_props)) =>
   261            Toplevel.print o (Toplevel.theory_to_proof (process_spec (SOME axname) cos alt_props))))
   262 
   263 end