src/HOL/HOLCF/Tools/Domain/domain.ML
author wenzelm
Thu, 15 Mar 2012 20:07:00 +0100
changeset 47823 94aa7b81bcf6
parent 47821 b8c7eb0c2f89
child 47836 5c6955f487e5
permissions -rw-r--r--
prefer formally checked @{keyword} parser;
     1 (*  Title:      HOL/HOLCF/Tools/Domain/domain.ML
     2     Author:     David von Oheimb
     3     Author:     Brian Huffman
     4 
     5 Theory extender for domain command, including theory syntax.
     6 *)
     7 
     8 signature DOMAIN =
     9 sig
    10   val add_domain_cmd:
    11       ((string * string option) list * binding * mixfix *
    12        (binding * (bool * binding option * string) list * mixfix) list) list
    13       -> theory -> theory
    14 
    15   val add_domain:
    16       ((string * sort) list * binding * mixfix *
    17        (binding * (bool * binding option * typ) list * mixfix) list) list
    18       -> theory -> theory
    19 
    20   val add_new_domain_cmd:
    21       ((string * string option) list * binding * mixfix *
    22        (binding * (bool * binding option * string) list * mixfix) list) list
    23       -> theory -> theory
    24 
    25   val add_new_domain:
    26       ((string * sort) list * binding * mixfix *
    27        (binding * (bool * binding option * typ) list * mixfix) list) list
    28       -> theory -> theory
    29 end
    30 
    31 structure Domain : DOMAIN =
    32 struct
    33 
    34 open HOLCF_Library
    35 
    36 fun first  (x,_,_) = x
    37 fun second (_,x,_) = x
    38 
    39 (* ----- calls for building new thy and thms -------------------------------- *)
    40 
    41 type info =
    42      Domain_Take_Proofs.iso_info list * Domain_Take_Proofs.take_induct_info
    43 
    44 fun add_arity ((b, sorts, mx), sort) thy : theory =
    45   thy
    46   |> Sign.add_types_global [(b, length sorts, mx)]
    47   |> AxClass.axiomatize_arity (Sign.full_name thy b, sorts, sort)
    48 
    49 fun gen_add_domain
    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)
    56     (thy : theory) =
    57   let
    58     val dtnvs : (binding * typ list * mixfix) list =
    59       let
    60         fun prep_tvar (a, s) = TFree (a, prep_sort thy s)
    61       in
    62         map (fn (vs, dbind, mx, _) =>
    63                 (dbind, map prep_tvar vs, mx)) raw_specs
    64       end
    65 
    66     fun thy_arity (dbind, tvars, mx) =
    67       ((dbind, map (snd o dest_TFree) tvars, mx), arg_sort false)
    68 
    69     (* this theory is used just for parsing and error checking *)
    70     val tmp_thy = thy
    71       |> Theory.copy
    72       |> fold (add_arity o thy_arity) dtnvs
    73 
    74     val dbinds : binding list =
    75         map (fn (_,dbind,_,_) => dbind) raw_specs
    76     val raw_rhss :
    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
    81 
    82     val all_cons = map (Binding.name_of o first) (flat raw_rhss)
    83     val _ =
    84       case duplicates (op =) all_cons of 
    85         [] => false | dups => error ("Duplicate constructors: " 
    86                                       ^ commas_quote dups)
    87     val all_sels =
    88       (map Binding.name_of o map_filter second o maps second) (flat raw_rhss)
    89     val _ =
    90       case duplicates (op =) all_sels of
    91         [] => false | dups => error("Duplicate selectors: "^commas_quote dups)
    92 
    93     fun test_dupl_tvars s =
    94       case duplicates (op =) (map(fst o dest_TFree)s) of
    95         [] => false | dups => error("Duplicate type arguments: " 
    96                                     ^commas_quote dups)
    97     val _ = exists test_dupl_tvars (map snd dtnvs')
    98 
    99     val sorts : (string * sort) list =
   100       let val all_sorts = map (map dest_TFree o snd) dtnvs'
   101       in
   102         case distinct (eq_set (op =)) all_sorts of
   103           [sorts] => sorts
   104         | _ => error "Mutually recursive domains must have same type parameters"
   105       end
   106 
   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)
   115       end
   116 
   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
   126           NONE =>
   127             let val no_rec' =
   128                   if no_rec = NONE then
   129                     if Symtab.defined rec_tab s then NONE else SOME s
   130                   else no_rec
   131             in Type (s, map (check_rec no_rec') Ts) end
   132         | SOME typevars =>
   133           if typevars <> Ts
   134           then error ("Recursion of type " ^ 
   135                       quote (Syntax.string_of_typ_global tmp_thy T) ^ 
   136                       " with different arguments")
   137           else (case no_rec of
   138                   NONE => T
   139                 | SOME c =>
   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"
   144 
   145     fun prep_arg (lazy, sel, raw_T) =
   146       let
   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
   155 
   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)
   160 
   161     val absTs : typ list = map Type dtnvs'
   162     val repTs : typ list = map mk_rhs_typ rhss
   163 
   164     val iso_spec : (binding * mixfix * (typ * typ)) list =
   165         map (fn ((dbind, _, mx), eq) => (dbind, mx, eq))
   166           (dtnvs ~~ (absTs ~~ repTs))
   167 
   168     val ((iso_infos, take_info), thy) = add_isos iso_spec thy
   169 
   170     val (constr_infos, thy) =
   171         thy
   172           |> fold_map (fn ((dbind, cons), info) =>
   173                 Domain_Constructors.add_domain_constructors dbind cons info)
   174              (dbinds ~~ rhss ~~ iso_infos)
   175 
   176     val (_, thy) =
   177         Domain_Induction.comp_theorems
   178           dbinds take_info constr_infos thy
   179   in
   180     thy
   181   end
   182 
   183 fun define_isos (spec : (binding * mixfix * (typ * typ)) list) =
   184   let
   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
   188   in
   189     Domain_Isomorphism.domain_isomorphism (map prep spec)
   190   end
   191 
   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"}
   194 
   195 fun read_sort thy (SOME s) = Syntax.read_sort_global thy s
   196   | read_sort thy NONE = Sign.defaultS thy
   197 
   198 (* Adapted from src/HOL/Tools/Datatype/datatype_data.ML *)
   199 fun read_typ thy sorts str =
   200   let
   201     val ctxt = Proof_Context.init_global thy
   202       |> fold (Variable.declare_typ o TFree) sorts
   203   in Syntax.read_typ ctxt str end
   204 
   205 fun cert_typ sign sorts raw_T =
   206   let
   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
   210     val _ =
   211       case duplicates (op =) (map fst sorts') of
   212         [] => ()
   213       | dups => error ("Inconsistent sort constraints for " ^ commas dups)
   214   in T end
   215 
   216 val add_domain =
   217     gen_add_domain (K I) cert_typ Domain_Axioms.add_axioms pcpo_arg
   218 
   219 val add_new_domain =
   220     gen_add_domain (K I) cert_typ define_isos rep_arg
   221 
   222 val add_domain_cmd =
   223     gen_add_domain read_sort read_typ Domain_Axioms.add_axioms pcpo_arg
   224 
   225 val add_new_domain_cmd =
   226     gen_add_domain read_sort read_typ define_isos rep_arg
   227 
   228 
   229 (** outer syntax **)
   230 
   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))
   237 
   238 val cons_decl =
   239   Parse.binding -- Scan.repeat dest_decl -- Parse.opt_mixfix
   240 
   241 val domain_decl =
   242   (Parse.type_args_constrained -- Parse.binding -- Parse.opt_mixfix) --
   243     (@{keyword "="} |-- Parse.enum1 "|" cons_decl)
   244 
   245 val domains_decl =
   246   Scan.optional (@{keyword "("} |-- (@{keyword "unsafe"} >> K true) --| @{keyword ")"}) false --
   247     Parse.and_list1 domain_decl
   248 
   249 fun mk_domain
   250     (unsafe : bool,
   251      doms : ((((string * string option) list * binding) * mixfix) *
   252              ((binding * (bool * binding option * string) list) * mixfix) list) list ) =
   253   let
   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
   258   in
   259     if unsafe
   260     then add_domain_cmd specs
   261     else add_new_domain_cmd specs
   262   end
   263 
   264 val _ =
   265   Outer_Syntax.command "domain" "define recursive domains (HOLCF)"
   266     Keyword.thy_decl (domains_decl >> (Toplevel.theory o mk_domain))
   267 
   268 end