define_type : {name :string, type_spec :term frag list, fixities : fixity list} -> thm
The type_spec argument to define_type must be a quotation of the form:
`op = C1 of ty => ... => ty | C2 of ty=> ...=>ty | ... | Cn of ty=> ... =>ty`
where op is the name of the type constant or type operator to be
defined, C1, ..., Cn are identifiers, and each ty is either a (logical)
type expression valid in the current theory (in which case ty must not
contain op) or just the identifier `op' itself.
A quotation of this form describes an n-ary type operator op, where n is the number of distinct type variables in the types ty on the right hand side of the equation. If n is zero then op is a type constant; otherwise op is an n-ary type operator. The type described by the specification has n distinct constructors C1, ..., Cn. Each constructor Ci is a function that takes arguments whose types are given by the associated type expressions ty in the specification. If one or more of the type expressions ty is the type op itself, then the equation specifies a recursive data type. In any specification, at least one constructor must be non-recursive, i.e. all its arguments must have types which already exist in the current theory.
Given a type specification of the form described above, define_type makes an appropriate type definition for the type operator op. It then makes appropriate definitions for the constants C1, ..., Cn, and automatically proves a theorem that states an abstract characterization of the newly-defined type op. This theorem, which is stored in the current theory segment under the name supplied as the first argument and also returned by define_type, has the form of a `primitive recursion theorem' for the concrete type op (see the examples given below). This property provides an abstract characterization of the type op which is both succinct and complete, in the sense that it completely determines the structure of the values of op up to isomorphism.
define_type{type_spec = `op = C1 of ty=>...=>ty | ... | Cn of ty=>...=>ty`, name, fixities}fails if HOL is not in draft mode; if op is already the name of a type constant or type operator in the current theory; if the supplied constant names C1, ..., Cn are not distinct; if any one of C1, ..., Cn is already a constant in the current theory or is not an allowed name for a constant; if ABS_op or REP_op are already constants in the current theory; if there is already an axiom, definition, constant specification or type definition stored under either the name op_TY_DEF or the name op_ISO_DEF in the current theory segment; if there is already a theorem stored under the name `name` in the current theory segment; or (finally) if the input type specification does not conform in any other respect to the syntax described above.
- define_type{name = "tri_DEF", type_spec = `tri = ONE | TWO | THREE`, fixities = [Prefix,Prefix,Prefix]} |- !e0 e1 e2. ?! fn. (fn ONE = e0) /\ (fn TWO = e1) /\ (fn THREE = e2)The theorem returned is a degenerate `primitive recursion' theorem for the concrete type tri. An example of a recursive type that can be defined using define_type is a type of binary trees:
- define_type {type_spec = `btree = LEAF of 'a | NODE of btree => btree`, name = "tree_DEF", fixities = [Prefix,Prefix]} |- !f0 f1. ?! fn. (!x. fn(LEAF x) = f0 x) /\ (!b1 b2. fn(NODE b1 b2) = f1(fn b1)(fn b2)b1 b2)The theorem returned by define_type in this case asserts the unique existence of functions defined by primitive recursion over labelled binary trees.
Note that the type being defined may not occur as a proper subtype in
any of the types of the arguments of the constructors:
- define_type{type_spec = `ty = NUM of num | FUN of (ty -> ty)`,
name = "num_funcs", fixities = [Prefix, Prefix]};
Exception raised at Term.make_type_clause.check:
recursive occurrence of defined type is deeper than the first level
In this example, there is an error because ty occurs within the
type expression (ty -> ty).