1 (******************************************************************************)
3 (* DESCRIPTION : Vague approximation in ML to Boyer-Moore "shell" principle *)
5 (* READS FILES : <none> *)
6 (* WRITES FILES : <none> *)
8 (* AUTHOR : R.J.Boulton *)
9 (* DATE : 8th May 1991 *)
11 (* LAST MODIFIED : R.J.Boulton *)
12 (* DATE : 12th October 1992 *)
14 (* LAST MODIFIED : P. Papapanagiotou (University of Edinburgh) *)
15 (* DATE : July 2009 *)
16 (******************************************************************************)
18 (*----------------------------------------------------------------------------*)
19 (* ML datatype for holding information about a recursive logical type. *)
20 (*----------------------------------------------------------------------------*)
22 type constructor_info =
23 string * (* Constructor name *)
24 hol_type list * (* Argument types *)
25 (string * thm) list;; (* Accessor functions *)
29 {arg_types : hol_type list; (* Argument types for type constructor *)
31 constructor_info list; (* Constructors for the type *)
32 axiom : thm; (* Type axiom *)
33 induct : thm; (* Induction theorem *)
34 cases : thm; (* Cases theorem *)
35 distinct : thm list; (* Constructors distinct *)
36 one_one : thm list; (* Constructors one-one *)
37 struct_conv : conv -> conv};;
39 type shell = Shell of string * shell_info;;
41 (*----------------------------------------------------------------------------*)
42 (* Reference variable holding the currently defined system shells. *)
43 (*----------------------------------------------------------------------------*)
45 let system_shells = ref ([]:shell list);;
47 (*----------------------------------------------------------------------------*)
48 (* Function to find the details of a named shell from a list of shells. *)
49 (*----------------------------------------------------------------------------*)
51 let rec shell_info (shl:shell list) name =
53 then failwith "shell_info"
54 else match (hd shl) with Shell (sh_name,info) ->
57 else shell_info (tl shl) name);;
59 (*----------------------------------------------------------------------------*)
60 (* Function to find the details of a named shell from the shells currently *)
61 (* defined in the system. *)
62 (*----------------------------------------------------------------------------*)
64 let sys_shell_info name = shell_info !system_shells name;;
66 (*----------------------------------------------------------------------------*)
67 (* Functions to extract the components of shell information. *)
68 (*----------------------------------------------------------------------------*)
69 let shell_constructors info = info.constructors;;
70 let shell_accessor_thms info =
71 ((map snd) o flat o (map thd3) o shell_constructors) info;;
72 let shell_arg_types info = info.arg_types;;
75 let shell_arg_types info = fst info
76 and shell_constructors info = (fst o snd) info
77 and shell_axiom info = (fst o snd o snd) info
78 and shell_induct info = (fst o snd o snd o snd) info
79 and shell_cases info = (fst o snd o snd o snd o snd) info
80 and shell_distinct info = (fst o snd o snd o snd o snd o snd) info
81 and shell_one_one info = (fst o snd o snd o snd o snd o snd o snd) info
82 and shell_struct_conv info = (snd o snd o snd o snd o snd o snd o snd) info;;
85 (*----------------------------------------------------------------------------*)
86 (* Function to extract details of a named constructor from shell information. *)
87 (*----------------------------------------------------------------------------*)
89 let shell_constructor name (info:shell_info) =
90 let rec shell_constructor' name triples =
92 then failwith "shell_constructor"
93 else let (con_name,arg_types,accessors) = (hd triples)
94 in if (con_name = name)
95 then (arg_types,accessors)
96 else shell_constructor' name (tl triples)
97 in shell_constructor' name (info.constructors);;
99 (*----------------------------------------------------------------------------*)
100 (* Functions to extract the argument types and the accessor functions for a *)
101 (* particular constructor. The source is a set of shell information. *)
102 (*----------------------------------------------------------------------------*)
104 let shell_constructor_arg_types name info =
105 fst (shell_constructor name info)
106 and shell_constructor_accessors name info =
107 snd (shell_constructor name info);;
109 (*----------------------------------------------------------------------------*)
110 (* shells : void -> string list *)
112 (* Function to compute the names of the currently defined system shells. *)
113 (*----------------------------------------------------------------------------*)
116 let rec shells' shl =
119 else match (hd shl) with (Shell (name,_)) -> (name::(shells' (tl shl)))
120 in shells' !system_shells;;
122 (*----------------------------------------------------------------------------*)
123 (* all_constructors : void -> string list *)
125 (* Returns a list of all the shell constructors (and bottom values) available *)
127 (*----------------------------------------------------------------------------*)
129 let all_constructors () =
130 flat (map (map fst3 o shell_constructors o sys_shell_info) (shells ()));;
132 (*----------------------------------------------------------------------------*)
133 (* all_accessors : void -> string list *)
135 (* Returns a list of all the shell accessors available in the system. *)
136 (*----------------------------------------------------------------------------*)
138 let all_accessors () =
139 flat (map (flat o map (map fst o thd3) o shell_constructors o
140 sys_shell_info) (shells ()));;
142 let all_accessor_thms () =
143 flat (map (shell_accessor_thms o sys_shell_info) (shells ()));;
145 (*----------------------------------------------------------------------------*)
146 (* `Shell' for natural numbers. *)
147 (*----------------------------------------------------------------------------*)
150 let axiom = num_Axiom
151 and induct = num_INDUCTION
152 and cases = num_CASES
153 and distinct = [NOT_SUC]
154 and one_one = [SUC_INJ]
160 [("0",[],[]);("SUC",[`:num`],[("PRE",CONJUNCT2 PRE)])];
166 struct_conv = ONE_STEP_RECTY_EQ_CONV
167 (induct,distinct,one_one)});;
169 (*----------------------------------------------------------------------------*)
170 (* `Shell' for lists. *)
171 (*----------------------------------------------------------------------------*)
174 let axiom = new_axiom `!x f. ?!fn1. (fn1 [] = x) /\ (!h t. fn1 (CONS h t) = f (fn1 t) h t)`
175 (* |- !x f. ?!fn1. (fn1 [] = x) /\ (!h t. fn1 (CONS h t) = f (fn1 t) h t) *)
176 and induct = list_INDUCT
177 and cases = list_CASES
178 and distinct = [NOT_CONS_NIL]
179 and one_one = [CONS_11]
182 {arg_types = [`:'a`];
186 [`:'a`;`:('a)list`],[("HD",HD);("TL",TL)])];
192 struct_conv = ONE_STEP_RECTY_EQ_CONV
193 (induct,distinct,one_one)});;
195 (*----------------------------------------------------------------------------*)
196 (* Set-up the system shell to reflect the basic HOL system. *)
197 (*----------------------------------------------------------------------------*)
199 system_shells := [list_shell;num_shell];;
201 (*----------------------------------------------------------------------------*)
202 (* define_shell : string -> string -> (string # string list) list -> void *)
204 (* Function for defining a new HOL type together with accessor functions, and *)
205 (* making a new Boyer-Moore shell from these definitions. If the type already *)
206 (* exists the function attempts to load the corresponding theorems from the *)
207 (* current theory hierarchy and use them to make the shell. *)
209 (* The first two arguments correspond to the arguments taken by `define_type' *)
210 (* and the third argument defines the accessor functions. This is a list of *)
211 (* constructor names each with names of accessors. The function assumes that *)
212 (* there are no accessors for a constructor that doesn't appear in the list, *)
213 (* so it is not necessary to include an entry for a nullary constructor. For *)
214 (* other constructors there must be one accessor name for each argument and *)
215 (* they should be given in the correct order. The function ignores any item *)
216 (* in the list with a constructor name that does not belong to the type. *)
218 (* The constructor and accessor names must all be distinct and must not be *)
219 (* the names of existing constants. *)
223 (* define_shell `sexp` `sexp = Nil | Atom * | Cons sexp sexp` *)
224 (* [(`Atom`,[`Tok`]);(`Cons`,[`Car`;`Cdr`])];; *)
226 (* This results in the following theorems being stored in the current theory *)
227 (* (or these are the theorems the function would expect to find in the theory *)
228 (* hierarchy if the type already exists): *)
230 (* sexp (type axiom) *)
231 (* sexp_Induct (induction theorem) *)
232 (* sexp_one_one (injectivity of constructors) *)
233 (* sexp_distinct (distinctness of constructors) *)
234 (* sexp_cases (cases theorem) *)
236 (* The following definitions for the accessor functions are also stored: *)
238 (* Tok |- !x. Tok(Atom x) = x *)
239 (* Car |- !s1 s2. Car(Cons s1 s2) = s1 *)
240 (* Cdr |- !s1 s2. Cdr(Cons s1 s2) = s2 *)
242 (* In certain cases the distinctness or injectivity theorems may not exist, *)
243 (* when nothing is saved for them. *)
245 (* Finally, a new Boyer-Moore shell is added based on the definitions and *)
247 (*----------------------------------------------------------------------------*)
249 let define_shell name syntax accessors =
253 then failwith `find_theory`
254 else if can (theorem (hd l)) s
259 let mk_def_eq (name,comb,arg) =
260 let ty = mk_type(`fun`,[type_of comb;type_of arg])
261 in mk_eq(mk_comb(mk_var(name,ty),comb),arg)
263 let define_accessor axiom (name,tm) =
264 (name,new_recursive_definition false axiom name tm)
266 let define_accessors axiom (comb,specs) =
267 map (\(name,arg). define_accessor axiom (name,mk_def_eq (name,comb,arg)))
270 if (mem name (shells ()))
271 then failwith `define_shell -- shell already exists`
273 let defined = is_type name
276 then (find_theory name ?
277 failwith (`define_shell -- no axiom found for type ` ^ name))
278 else current_theory ()
281 then theorem theory name
282 else define_type name syntax
285 then theorem theory (name ^ `_Induct`)
286 else save_thm((name ^ `_Induct`),prove_induction_thm name_Axiom)
289 then (CONJUNCTS (theorem theory (name ^ `_one_one`))
290 ?\s if (can prove_constructors_one_one name_Axiom)
293 else ((CONJUNCTS o save_thm)
294 ((name ^ `_one_one`),prove_constructors_one_one name_Axiom)
298 then (CONJUNCTS (theorem theory (name ^ `_distinct`))
299 ?\s if (can prove_constructors_distinct name_Axiom)
302 else ((CONJUNCTS o save_thm)
303 ((name ^ `_distinct`),prove_constructors_distinct name_Axiom)
307 then theorem theory (name ^ `_cases`)
308 else save_thm((name ^ `_cases`),prove_cases_thm name_Induct)
309 in let ty = (type_of o fst o dest_forall o concl) name_cases
310 in let ty_args = snd (dest_type ty)
311 in let cases = (disjuncts o snd o dest_forall o concl) name_cases
312 in let combs = map (rhs o snd o strip_exists) cases
313 in let constrs_and_args = map (((fst o dest_const) # I) o strip_comb) combs
314 in let (constrs,arg_types) =
315 split (map (I # (map type_of)) constrs_and_args)
317 map (\(c,args). combine((snd (assoc c accessors) ? []),args)
319 (`define_shell -- ` ^
320 `incorrect number of accessors for constructor ` ^ c))
324 then map (map ((\acc. (acc,definition theory acc)) o fst)) acc_specs
325 else map (define_accessors name_Axiom) (combine (combs,acc_specs))
327 Shell (name,ty_args,combine(constrs,combine(arg_types,acc_defs)),
328 name_Axiom,name_Induct,name_cases,
329 name_distincts,name_one_ones,
330 ONE_STEP_RECTY_EQ_CONV
331 (name_Induct,name_distincts,name_one_ones))
332 in do (system_shells := name_shell.system_shells);;