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