(* ========================================================================= *) (* Abstract type of HOL name-carrying terms and manipulation functions. *) (* *) (* John Harrison, University of Cambridge Computer Laboratory *) (* *) (* (c) Copyright, University of Cambridge 1998 *) (* (c) Copyright, John Harrison 1998-2007 *) (* ========================================================================= *) module type Hol_term_primitives = sig type term = private Var of string * hol_type | Const of string * hol_type | Comb of term * term | Abs of term * term val constants : unit -> (string * hol_type) list val get_const_type : string -> hol_type val new_constant : string * hol_type -> unit val type_of : term -> hol_type val aconv : term -> term -> bool val is_var : term -> bool val is_const : term -> bool val is_abs : term -> bool val is_comb : term -> bool val mk_var : string * hol_type -> term val mk_const : string * (hol_type * hol_type) list -> term val mk_abs : term * term -> term val mk_comb : term * term -> term val dest_var : term -> string * hol_type val dest_const : term -> string * hol_type val dest_comb : term -> term * term val dest_abs : term -> term * term val frees : term -> term list val freesl : term list -> term list val freesin : term list -> term -> bool val vfree_in : term -> term -> bool val type_vars_in_term : term -> hol_type list val variant : term list -> term -> term val vsubst : (term * term) list -> term -> term val inst : (hol_type * hol_type) list -> term -> term end;; (* ------------------------------------------------------------------------- *) (* This is the implementation of those primitives. *) (* ------------------------------------------------------------------------- *) module Term : Hol_term_primitives = struct type term = Var of string * hol_type | Const of string * hol_type | Comb of term * term | Abs of term * term (* ------------------------------------------------------------------------- *) (* List of term constants and their types. *) (* *) (* We begin with just equality (over all types). Later, the Hilbert choice *) (* operator is added. All other new constants are defined. *) (* ------------------------------------------------------------------------- *) let the_term_constants = ref ["=", mk_fun_ty aty (mk_fun_ty aty bool_ty)] (* ------------------------------------------------------------------------- *) (* Return all the defined constants with generic types. *) (* ------------------------------------------------------------------------- *) let constants() = !the_term_constants (* ------------------------------------------------------------------------- *) (* Gets type of constant if it succeeds. *) (* ------------------------------------------------------------------------- *) let get_const_type s = assoc s (!the_term_constants) (* ------------------------------------------------------------------------- *) (* Declare a new constant. *) (* ------------------------------------------------------------------------- *) let new_constant(name,ty) = if can get_const_type name then failwith ("new_constant: constant "^name^" has already been declared") else the_term_constants := (name,ty)::(!the_term_constants) (* ------------------------------------------------------------------------- *) (* Finds the type of a term (assumes it is well-typed). *) (* ------------------------------------------------------------------------- *) let rec type_of tm = match tm with Var(_,ty) -> ty | Const(_,ty) -> ty | Comb(s,_) -> hd(tl(snd(dest_type(type_of s)))) | Abs(Var(_,ty),t) -> mk_fun_ty ty (type_of t) (* ------------------------------------------------------------------------- *) (* Tests for alpha-convertibility (equality ignoring names in abstractions). *) (* ------------------------------------------------------------------------- *) let aconv = let rec alphavars env tm1 tm2 = match env with [] -> tm1 = tm2 | (t1,t2)::oenv -> (t1 = tm1 & t2 = tm2) or (t1 <> tm1 & t2 <> tm2 & alphavars oenv tm1 tm2) in let rec raconv env tm1 tm2 = (tm1 == tm2 & env = []) or match (tm1,tm2) with Var(_,_),Var(_,_) -> alphavars env tm1 tm2 | Const(_,_),Const(_,_) -> tm1 = tm2 | Comb(s1,t1),Comb(s2,t2) -> raconv env s1 s2 & raconv env t1 t2 | Abs(Var(_,ty1) as x1,t1),Abs(Var(_,ty2) as x2,t2) -> ty1 = ty2 & raconv ((x1,x2)::env) t1 t2 | _ -> false in fun tm1 tm2 -> raconv [] tm1 tm2 (* ------------------------------------------------------------------------- *) (* Primitive discriminators. *) (* ------------------------------------------------------------------------- *) let is_var = function (Var(_,_)) -> true | _ -> false let is_const = function (Const(_,_)) -> true | _ -> false let is_abs = function (Abs(_,_)) -> true | _ -> false let is_comb = function (Comb(_,_)) -> true | _ -> false (* ------------------------------------------------------------------------- *) (* Primitive constructors. *) (* ------------------------------------------------------------------------- *) let mk_var(v,ty) = Var(v,ty) let mk_const(name,theta) = let uty = try get_const_type name with Failure _ -> failwith "mk_const: not a constant name" in Const(name,type_subst theta uty) let mk_abs(bvar,bod) = match bvar with Var(_,_) -> Abs(bvar,bod) | _ -> failwith "mk_abs: not a variable" let mk_comb(f,a) = match type_of f with Tyapp("fun",[ty;_]) when ty = type_of a -> Comb(f,a) | _ -> failwith "mk_comb: types do not agree" (* ------------------------------------------------------------------------- *) (* Primitive destructors. *) (* ------------------------------------------------------------------------- *) let dest_var = function (Var(s,ty)) -> s,ty | _ -> failwith "dest_var: not a variable" let dest_const = function (Const(s,ty)) -> s,ty | _ -> failwith "dest_const: not a constant" let dest_comb = function (Comb(f,x)) -> f,x | _ -> failwith "dest_comb: not a combination" let dest_abs = function (Abs(v,b)) -> v,b | _ -> failwith "dest_abs: not an abstraction" (* ------------------------------------------------------------------------- *) (* Finds the variables free in a term (list of terms). *) (* ------------------------------------------------------------------------- *) let rec frees tm = match tm with Var(_,_) -> [tm] | Const(_,_) -> [] | Abs(bv,bod) -> subtract (frees bod) [bv] | Comb(s,t) -> union (frees s) (frees t) let freesl tml = itlist (union o frees) tml [] (* ------------------------------------------------------------------------- *) (* Whether all free variables in a term appear in a list. *) (* ------------------------------------------------------------------------- *) let rec freesin acc tm = match tm with Var(_,_) -> mem tm acc | Const(_,_) -> true | Abs(bv,bod) -> freesin (bv::acc) bod | Comb(s,t) -> freesin acc s & freesin acc t (* ------------------------------------------------------------------------- *) (* Whether a variable (or constant in fact) is free in a term. *) (* ------------------------------------------------------------------------- *) let rec vfree_in v tm = match tm with Abs(bv,bod) -> v <> bv & vfree_in v bod | Comb(s,t) -> vfree_in v s or vfree_in v t | _ -> tm = v (* ------------------------------------------------------------------------- *) (* Finds the type variables (free) in a term. *) (* ------------------------------------------------------------------------- *) let rec type_vars_in_term tm = match tm with Var(_,ty) -> tyvars ty | Const(_,ty) -> tyvars ty | Comb(s,t) -> union (type_vars_in_term s) (type_vars_in_term t) | Abs(Var(_,ty),t) -> union (tyvars ty) (type_vars_in_term t) (* ------------------------------------------------------------------------- *) (* For name-carrying syntax, we need this early. *) (* ------------------------------------------------------------------------- *) let rec variant avoid v = if not(exists (vfree_in v) avoid) then v else match v with Var(s,ty) -> variant avoid (Var(s^"'",ty)) | _ -> failwith "variant: not a variable" (* ------------------------------------------------------------------------- *) (* Substitution primitive (substitution for variables only!) *) (* ------------------------------------------------------------------------- *) let vsubst = let rec vsubst ilist tm = match tm with Var(_,_) -> rev_assocd tm ilist tm | Const(_,_) -> tm | Comb(s,t) -> let s' = vsubst ilist s and t' = vsubst ilist t in if s' == s & t' == t then tm else Comb(s',t') | Abs(v,s) -> let ilist' = filter (fun (t,x) -> x <> v) ilist in if ilist' = [] then tm else let s' = vsubst ilist' s in if s' == s then tm else if exists (fun (t,x) -> vfree_in v t & vfree_in x s) ilist' then let v' = variant [s'] v in Abs(v',vsubst ((v',v)::ilist') s) else Abs(v,s') in fun theta -> if theta = [] then (fun tm -> tm) else if forall (fun (t,x) -> type_of t = snd(dest_var x)) theta then vsubst theta else failwith "vsubst: Bad substitution list" (* ------------------------------------------------------------------------- *) (* Type instantiation primitive. *) (* ------------------------------------------------------------------------- *) exception Clash of term let inst = let rec inst env tyin tm = match tm with Var(n,ty) -> let ty' = type_subst tyin ty in let tm' = if ty' == ty then tm else Var(n,ty') in if rev_assocd tm' env tm = tm then tm' else raise (Clash tm') | Const(c,ty) -> let ty' = type_subst tyin ty in if ty' == ty then tm else Const(c,ty') | Comb(f,x) -> let f' = inst env tyin f and x' = inst env tyin x in if f' == f & x' == x then tm else Comb(f',x') | Abs(y,t) -> let y' = inst [] tyin y in let env' = (y,y')::env in try let t' = inst env' tyin t in if y' == y & t' == t then tm else Abs(y',t') with (Clash(w') as ex) -> if w' <> y' then raise ex else let ifrees = map (inst [] tyin) (frees t) in let y'' = variant ifrees y' in let z = Var(fst(dest_var y''),snd(dest_var y)) in inst env tyin (Abs(z,vsubst[z,y] t)) in fun tyin -> if tyin = [] then fun tm -> tm else inst [] tyin end;; include Term;;