src/HOL/Tools/specification_package.ML
author haftmann
Fri Feb 10 09:09:07 2006 +0100 (2006-02-10)
changeset 19008 14c1b2f5dda4
parent 18921 f47c46d7d654
child 19414 a21431e996bf
permissions -rw-r--r--
improved code generator devarification
     1 (*  Title:      HOL/Tools/specification_package.ML
     2     ID:         $Id$
     3     Author:     Sebastian Skalberg, TU Muenchen
     4 
     5 Package for defining constants by specification.
     6 *)
     7 
     8 signature SPECIFICATION_PACKAGE =
     9 sig
    10   val quiet_mode: bool ref
    11   val add_specification: string option -> (bstring * xstring * bool) list ->
    12     theory * thm -> theory * thm
    13 end
    14 
    15 structure SpecificationPackage: SPECIFICATION_PACKAGE =
    16 struct
    17 
    18 (* messages *)
    19 
    20 val quiet_mode = ref false
    21 fun message s = if ! quiet_mode then () else writeln s
    22 
    23 
    24 (* Actual code *)
    25 
    26 local
    27     val exE_some = thm "exE_some";
    28 
    29     fun mk_definitional [] arg = arg
    30       | mk_definitional ((thname,cname,covld)::cos) (thy,thm) =
    31         case HOLogic.dest_Trueprop (concl_of thm) of
    32             Const("Ex",_) $ P =>
    33             let
    34                 val ctype = domain_type (type_of P)
    35                 val cname_full = Sign.intern_const (sign_of thy) cname
    36                 val cdefname = if thname = ""
    37                                then Thm.def_name (Sign.base_name cname)
    38                                else thname
    39                 val def_eq = Logic.mk_equals (Const(cname_full,ctype),
    40                                               HOLogic.choice_const ctype $  P)
    41                 val (thms, thy') = PureThy.add_defs_i covld [((cdefname,def_eq),[])] thy
    42                 val thm' = [thm,hd thms] MRS exE_some
    43             in
    44                 mk_definitional cos (thy',thm')
    45             end
    46           | _ => raise THM ("Internal error: Bad specification theorem",0,[thm])
    47 
    48     fun mk_axiomatic axname cos arg =
    49         let
    50             fun process [] (thy,tm) =
    51                 let
    52                     val (thms, thy') = PureThy.add_axioms_i [((axname,HOLogic.mk_Trueprop tm),[])] thy
    53                 in
    54                     (thy',hd thms)
    55                 end
    56               | process ((thname,cname,covld)::cos) (thy,tm) =
    57                 case tm of
    58                     Const("Ex",_) $ P =>
    59                     let
    60                         val ctype = domain_type (type_of P)
    61                         val cname_full = Sign.intern_const (sign_of thy) cname
    62                         val cdefname = if thname = ""
    63                                        then Thm.def_name (Sign.base_name cname)
    64                                        else thname
    65                         val co = Const(cname_full,ctype)
    66                         val thy' = Theory.add_finals_i covld [co] thy
    67                         val tm' = case P of
    68                                       Abs(_, _, bodt) => subst_bound (co, bodt)
    69                                     | _ => P $ co
    70                     in
    71                         process cos (thy',tm')
    72                     end
    73                   | _ => raise TERM ("Internal error: Bad specification theorem",[tm])
    74         in
    75             process cos arg
    76         end
    77 
    78 in
    79 fun proc_exprop axiomatic cos arg =
    80     case axiomatic of
    81         SOME axname => mk_axiomatic axname cos (apsnd (HOLogic.dest_Trueprop o concl_of) arg)
    82       | NONE => mk_definitional cos arg
    83 end
    84 
    85 fun add_specification axiomatic cos arg =
    86     arg |> apsnd freezeT
    87         |> proc_exprop axiomatic cos
    88         |> apsnd standard
    89 
    90 fun add_spec x y (context, thm) =
    91   (Context.the_theory context, thm) |> add_specification x y |>> Context.Theory;
    92 
    93 
    94 (* Collect all intances of constants in term *)
    95 
    96 fun collect_consts (        t $ u,tms) = collect_consts (u,collect_consts (t,tms))
    97   | collect_consts (   Abs(_,_,t),tms) = collect_consts (t,tms)
    98   | collect_consts (tm as Const _,tms) = insert (op aconv) tm tms
    99   | collect_consts (            _,tms) = tms
   100 
   101 (* Complementing Type.varify... *)
   102 
   103 fun unvarify t fmap =
   104     let
   105         val fmap' = map Library.swap fmap
   106         fun unthaw (f as (a, S)) =
   107             (case AList.lookup (op =) fmap' a of
   108                  NONE => TVar f
   109                | SOME (b, _) => TFree (b, S))
   110     in
   111         map_term_types (map_type_tvar unthaw) t
   112     end
   113 
   114 (* The syntactic meddling needed to setup add_specification for work *)
   115 
   116 fun process_spec axiomatic cos alt_props thy =
   117     let
   118         fun zip3 [] [] [] = []
   119           | zip3 (x::xs) (y::ys) (z::zs) = (x,y,z)::zip3 xs ys zs
   120           | zip3 _ _ _ = error "SpecificationPackage.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 "SpecificationPackage.process_spec internal error"
   125 
   126         fun typ_equiv t u = Sign.typ_instance thy (t,u) andalso Sign.typ_instance thy (u,t);
   127 
   128         val rew_imps = alt_props |>
   129           map (ObjectLogic.atomize_cterm o Thm.read_cterm thy o rpair Term.propT o snd)
   130         val props' = rew_imps |>
   131           map (HOLogic.dest_Trueprop o term_of o snd o dest_equals o cprop_of)
   132 
   133         fun proc_single prop =
   134             let
   135                 val frees = Term.term_frees prop
   136                 val tsig = Sign.tsig_of (sign_of thy)
   137                 val _ = assert (forall (fn v => Type.of_sort tsig (type_of v,HOLogic.typeS)) frees)
   138                                "Specificaton: Only free variables of sort 'type' allowed"
   139                 val prop_closed = foldr (fn ((vname,T),prop) => HOLogic.mk_all (vname,T,prop)) prop (map dest_Free frees)
   140             in
   141                 (prop_closed,frees)
   142             end
   143 
   144         val props'' = map proc_single props'
   145         val frees = map snd props''
   146         val prop  = myfoldr HOLogic.mk_conj (map fst props'')
   147         val cprop = cterm_of thy (HOLogic.mk_Trueprop prop)
   148 
   149         val (prop_thawed,vmap) = Type.varify (prop,[])
   150         val thawed_prop_consts = collect_consts (prop_thawed,[])
   151         val (altcos,overloaded) = Library.split_list cos
   152         val (names,sconsts) = Library.split_list altcos
   153         val consts = map (term_of o Thm.read_cterm thy o rpair TypeInfer.logicT) sconsts
   154         val _ = assert (not (Library.exists (not o Term.is_Const) consts))
   155                        "Specification: Non-constant found as parameter"
   156 
   157         fun proc_const c =
   158             let
   159                 val c' = fst (Type.varify (c,[]))
   160                 val (cname,ctyp) = dest_Const c'
   161             in
   162                 case List.filter (fn t => let val (name,typ) = dest_Const t
   163                                      in name = cname andalso typ_equiv typ ctyp
   164                                      end) thawed_prop_consts of
   165                     [] => error ("Specification: No suitable instances of constant \"" ^ (Sign.string_of_term thy c) ^ "\" found")
   166                   | [cf] => unvarify cf vmap
   167                   | _ => error ("Specification: Several variations of \"" ^ (Sign.string_of_term thy c) ^ "\" found (try applying explicit type constraints)")
   168             end
   169         val proc_consts = map proc_const consts
   170         fun mk_exist (c,prop) =
   171             let
   172                 val T = type_of c
   173                 val cname = Sign.base_name (fst (dest_Const c))
   174                 val vname = if Syntax.is_identifier cname
   175                             then cname
   176                             else "x"
   177             in
   178                 HOLogic.exists_const T $ Abs(vname,T,Term.abstract_over (c,prop))
   179             end
   180         val ex_prop = foldr mk_exist prop proc_consts
   181         val cnames = map (fst o dest_Const) proc_consts
   182         fun post_process (arg as (thy,thm)) =
   183             let
   184                 fun inst_all thy (thm,v) =
   185                     let
   186                         val cv = cterm_of thy v
   187                         val cT = ctyp_of_term cv
   188                         val spec' = instantiate' [SOME cT] [NONE,SOME cv] spec
   189                     in
   190                         thm RS spec'
   191                     end
   192                 fun remove_alls frees thm = Library.foldl (inst_all (sign_of_thm thm)) (thm,frees)
   193                 fun process_single ((name,atts),rew_imp,frees) args =
   194                     let
   195                         fun undo_imps thm =
   196                             equal_elim (symmetric rew_imp) thm
   197 
   198                         fun add_final (arg as (thy, thm)) =
   199                             if name = ""
   200                             then arg |> Library.swap
   201                             else (writeln ("  " ^ name ^ ": " ^ (string_of_thm thm));
   202                                   PureThy.store_thm ((name, thm), []) thy)
   203                     in
   204                         args |> apsnd (remove_alls frees)
   205                              |> apsnd undo_imps
   206                              |> apsnd standard
   207                              |> Thm.theory_attributes (map (Attrib.attribute thy) atts)
   208                              |> add_final
   209                              |> Library.swap
   210                     end
   211 
   212                 fun process_all [proc_arg] args =
   213                     process_single proc_arg args
   214                   | process_all (proc_arg::rest) (thy,thm) =
   215                     let
   216                         val single_th = thm RS conjunct1
   217                         val rest_th   = thm RS conjunct2
   218                         val (thy',_)  = process_single proc_arg (thy,single_th)
   219                     in
   220                         process_all rest (thy',rest_th)
   221                     end
   222                   | process_all [] _ = error "SpecificationPackage.process_spec internal error"
   223                 val alt_names = map fst alt_props
   224                 val _ = if exists (fn(name,_) => not (name = "")) alt_names
   225                         then writeln "specification"
   226                         else ()
   227             in
   228                 arg |> apsnd freezeT
   229                     |> process_all (zip3 alt_names rew_imps frees)
   230             end
   231             fun post_proc (context, th) =
   232                 post_process (Context.theory_of context, th) |>> Context.Theory;
   233     in
   234       IsarThy.theorem_i PureThy.internalK
   235         ("", [add_spec axiomatic (zip3 names cnames overloaded), post_proc])
   236         (HOLogic.mk_Trueprop ex_prop, ([], [])) thy
   237     end
   238 
   239 
   240 (* outer syntax *)
   241 
   242 local structure P = OuterParse and K = OuterKeyword in
   243 
   244 val opt_name = Scan.optional (P.name --| P.$$$ ":") ""
   245 val opt_overloaded = P.opt_keyword "overloaded";
   246 
   247 val specification_decl =
   248   P.$$$ "(" |-- Scan.repeat1 (opt_name -- P.term -- opt_overloaded) --| P.$$$ ")" --
   249           Scan.repeat1 (P.opt_thm_name ":" -- P.prop)
   250 
   251 val specificationP =
   252   OuterSyntax.command "specification" "define constants by specification" K.thy_goal
   253     (specification_decl >> (fn (cos,alt_props) =>
   254                                Toplevel.print o (Toplevel.theory_to_proof
   255                                                      (process_spec NONE cos alt_props))))
   256 
   257 val ax_specification_decl =
   258     P.name --
   259     (P.$$$ "(" |-- Scan.repeat1 (opt_name -- P.term -- opt_overloaded) --| P.$$$ ")" --
   260            Scan.repeat1 (P.opt_thm_name ":" -- P.prop))
   261 
   262 val ax_specificationP =
   263   OuterSyntax.command "ax_specification" "define constants by specification" K.thy_goal
   264     (ax_specification_decl >> (fn (axname,(cos,alt_props)) =>
   265                                Toplevel.print o (Toplevel.theory_to_proof
   266                                                      (process_spec (SOME axname) cos alt_props))))
   267 
   268 val _ = OuterSyntax.add_parsers [specificationP,ax_specificationP]
   269 
   270 end
   271 
   272 
   273 end