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