1 (* Title: HOL/HOLCF/Tools/Domain/domain.ML
2 Author: David von Oheimb
5 Theory extender for domain command, including theory syntax.
11 ((string * string option) list * binding * mixfix *
12 (binding * (bool * binding option * string) list * mixfix) list) list
16 ((string * sort) list * binding * mixfix *
17 (binding * (bool * binding option * typ) list * mixfix) list) list
20 val add_new_domain_cmd:
21 ((string * string option) list * binding * mixfix *
22 (binding * (bool * binding option * string) list * mixfix) list) list
26 ((string * sort) list * binding * mixfix *
27 (binding * (bool * binding option * typ) list * mixfix) list) list
31 structure Domain : DOMAIN =
37 fun second (_,x,_) = x
39 (* ----- calls for building new thy and thms -------------------------------- *)
42 Domain_Take_Proofs.iso_info list * Domain_Take_Proofs.take_induct_info
44 fun add_arity ((b, sorts, mx), sort) thy : theory =
46 |> Sign.add_types_global [(b, length sorts, mx)]
47 |> AxClass.axiomatize_arity (Sign.full_name thy b, sorts, sort)
50 (prep_sort : theory -> 'a -> sort)
51 (prep_typ : theory -> (string * sort) list -> 'b -> typ)
52 (add_isos : (binding * mixfix * (typ * typ)) list -> theory -> info * theory)
53 (arg_sort : bool -> sort)
54 (raw_specs : ((string * 'a) list * binding * mixfix *
55 (binding * (bool * binding option * 'b) list * mixfix) list) list)
58 val dtnvs : (binding * typ list * mixfix) list =
60 fun prep_tvar (a, s) = TFree (a, prep_sort thy s)
62 map (fn (vs, dbind, mx, _) =>
63 (dbind, map prep_tvar vs, mx)) raw_specs
66 fun thy_arity (dbind, tvars, mx) =
67 ((dbind, map (snd o dest_TFree) tvars, mx), arg_sort false)
69 (* this theory is used just for parsing and error checking *)
72 |> fold (add_arity o thy_arity) dtnvs
74 val dbinds : binding list =
75 map (fn (_,dbind,_,_) => dbind) raw_specs
77 (binding * (bool * binding option * 'b) list * mixfix) list list =
78 map (fn (_,_,_,cons) => cons) raw_specs
79 val dtnvs' : (string * typ list) list =
80 map (fn (dbind, vs, _) => (Sign.full_name thy dbind, vs)) dtnvs
82 val all_cons = map (Binding.name_of o first) (flat raw_rhss)
84 case duplicates (op =) all_cons of
85 [] => false | dups => error ("Duplicate constructors: "
88 (map Binding.name_of o map_filter second o maps second) (flat raw_rhss)
90 case duplicates (op =) all_sels of
91 [] => false | dups => error("Duplicate selectors: "^commas_quote dups)
93 fun test_dupl_tvars s =
94 case duplicates (op =) (map(fst o dest_TFree)s) of
95 [] => false | dups => error("Duplicate type arguments: "
97 val _ = exists test_dupl_tvars (map snd dtnvs')
99 val sorts : (string * sort) list =
100 let val all_sorts = map (map dest_TFree o snd) dtnvs'
102 case distinct (eq_set (op =)) all_sorts of
104 | _ => error "Mutually recursive domains must have same type parameters"
107 (* a lazy argument may have an unpointed type *)
108 (* unless the argument has a selector function *)
109 fun check_pcpo (lazy, sel, T) =
110 let val sort = arg_sort (lazy andalso is_none sel) in
111 if Sign.of_sort tmp_thy (T, sort) then ()
112 else error ("Constructor argument type is not of sort " ^
113 Syntax.string_of_sort_global tmp_thy sort ^ ": " ^
114 Syntax.string_of_typ_global tmp_thy T)
117 (* test for free type variables, illegal sort constraints on rhs,
118 non-pcpo-types and invalid use of recursive type
119 replace sorts in type variables on rhs *)
120 val rec_tab = Domain_Take_Proofs.get_rec_tab thy
121 fun check_rec _ (T as TFree (v,_)) =
122 if AList.defined (op =) sorts v then T
123 else error ("Free type variable " ^ quote v ^ " on rhs.")
124 | check_rec no_rec (T as Type (s, Ts)) =
125 (case AList.lookup (op =) dtnvs' s of
128 if no_rec = NONE then
129 if Symtab.defined rec_tab s then NONE else SOME s
131 in Type (s, map (check_rec no_rec') Ts) end
134 then error ("Recursion of type " ^
135 quote (Syntax.string_of_typ_global tmp_thy T) ^
136 " with different arguments")
140 error ("Illegal indirect recursion of type " ^
141 quote (Syntax.string_of_typ_global tmp_thy T) ^
142 " under type constructor " ^ quote c)))
143 | check_rec _ (TVar _) = error "extender:check_rec"
145 fun prep_arg (lazy, sel, raw_T) =
147 val T = prep_typ tmp_thy sorts raw_T
148 val _ = check_rec NONE T
149 val _ = check_pcpo (lazy, sel, T)
150 in (lazy, sel, T) end
151 fun prep_con (b, args, mx) = (b, map prep_arg args, mx)
152 fun prep_rhs cons = map prep_con cons
153 val rhss : (binding * (bool * binding option * typ) list * mixfix) list list =
154 map prep_rhs raw_rhss
156 fun mk_arg_typ (lazy, _, T) = if lazy then mk_upT T else T
157 fun mk_con_typ (_, args, _) =
158 if null args then oneT else foldr1 mk_sprodT (map mk_arg_typ args)
159 fun mk_rhs_typ cons = foldr1 mk_ssumT (map mk_con_typ cons)
161 val absTs : typ list = map Type dtnvs'
162 val repTs : typ list = map mk_rhs_typ rhss
164 val iso_spec : (binding * mixfix * (typ * typ)) list =
165 map (fn ((dbind, _, mx), eq) => (dbind, mx, eq))
166 (dtnvs ~~ (absTs ~~ repTs))
168 val ((iso_infos, take_info), thy) = add_isos iso_spec thy
170 val (constr_infos, thy) =
172 |> fold_map (fn ((dbind, cons), info) =>
173 Domain_Constructors.add_domain_constructors dbind cons info)
174 (dbinds ~~ rhss ~~ iso_infos)
177 Domain_Induction.comp_theorems
178 dbinds take_info constr_infos thy
183 fun define_isos (spec : (binding * mixfix * (typ * typ)) list) =
185 fun prep (dbind, mx, (lhsT, rhsT)) =
186 let val (_, vs) = dest_Type lhsT
187 in (map (fst o dest_TFree) vs, dbind, mx, rhsT, NONE) end
189 Domain_Isomorphism.domain_isomorphism (map prep spec)
192 fun pcpo_arg lazy = if lazy then @{sort cpo} else @{sort pcpo}
193 fun rep_arg lazy = if lazy then @{sort predomain} else @{sort "domain"}
195 fun read_sort thy (SOME s) = Syntax.read_sort_global thy s
196 | read_sort thy NONE = Sign.defaultS thy
198 (* Adapted from src/HOL/Tools/Datatype/datatype_data.ML *)
199 fun read_typ thy sorts str =
201 val ctxt = Proof_Context.init_global thy
202 |> fold (Variable.declare_typ o TFree) sorts
203 in Syntax.read_typ ctxt str end
205 fun cert_typ sign sorts raw_T =
207 val T = Type.no_tvars (Sign.certify_typ sign raw_T)
208 handle TYPE (msg, _, _) => error msg
209 val sorts' = Term.add_tfreesT T sorts
211 case duplicates (op =) (map fst sorts') of
213 | dups => error ("Inconsistent sort constraints for " ^ commas dups)
217 gen_add_domain (K I) cert_typ Domain_Axioms.add_axioms pcpo_arg
220 gen_add_domain (K I) cert_typ define_isos rep_arg
223 gen_add_domain read_sort read_typ Domain_Axioms.add_axioms pcpo_arg
225 val add_new_domain_cmd =
226 gen_add_domain read_sort read_typ define_isos rep_arg
231 val dest_decl : (bool * binding option * string) parser =
232 @{keyword "("} |-- Scan.optional (@{keyword "lazy"} >> K true) false --
233 (Parse.binding >> SOME) -- (@{keyword "::"} |-- Parse.typ) --| @{keyword ")"} >> Parse.triple1
234 || @{keyword "("} |-- @{keyword "lazy"} |-- Parse.typ --| @{keyword ")"}
235 >> (fn t => (true, NONE, t))
236 || Parse.typ >> (fn t => (false, NONE, t))
239 Parse.binding -- Scan.repeat dest_decl -- Parse.opt_mixfix
242 (Parse.type_args_constrained -- Parse.binding -- Parse.opt_mixfix) --
243 (@{keyword "="} |-- Parse.enum1 "|" cons_decl)
246 Scan.optional (@{keyword "("} |-- (@{keyword "unsafe"} >> K true) --| @{keyword ")"}) false --
247 Parse.and_list1 domain_decl
251 doms : ((((string * string option) list * binding) * mixfix) *
252 ((binding * (bool * binding option * string) list) * mixfix) list) list ) =
254 val specs : ((string * string option) list * binding * mixfix *
255 (binding * (bool * binding option * string) list * mixfix) list) list =
256 map (fn (((vs, t), mx), cons) =>
257 (vs, t, mx, map (fn ((c, ds), mx) => (c, ds, mx)) cons)) doms
260 then add_domain_cmd specs
261 else add_new_domain_cmd specs
265 Outer_Syntax.command "domain" "define recursive domains (HOLCF)"
266 Keyword.thy_decl (domains_decl >> (Toplevel.theory o mk_domain))