src/Pure/envir.ML
author haftmann
Tue Sep 06 08:30:43 2005 +0200 (2005-09-06)
changeset 17271 2756a73f63a5
parent 17224 a78339014063
child 17412 e26cb20ef0cc
permissions -rw-r--r--
introduced some new-style AList operations
     1 (*  Title:      Pure/envir.ML
     2     ID:         $Id$
     3     Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
     4     Copyright   1988  University of Cambridge
     5 
     6 Environments.  The type of a term variable / sort of a type variable is
     7 part of its name. The lookup function must apply type substitutions,
     8 since they may change the identity of a variable.
     9 *)
    10 
    11 signature ENVIR =
    12 sig
    13   type tenv
    14   datatype env = Envir of {asol: tenv, iTs: Type.tyenv, maxidx: int}
    15   val type_env: env -> Type.tyenv
    16   exception SAME
    17   val genvars: string -> env * typ list -> env * term list
    18   val genvar: string -> env * typ -> env * term
    19   val lookup: env * (indexname * typ) -> term option
    20   val lookup': tenv * (indexname * typ) -> term option
    21   val update: ((indexname * typ) * term) * env -> env
    22   val empty: int -> env
    23   val is_empty: env -> bool
    24   val above: int * env -> bool
    25   val vupdate: ((indexname * typ) * term) * env -> env
    26   val alist_of: env -> (indexname * (typ * term)) list
    27   val norm_term: env -> term -> term
    28   val norm_term_same: env -> term -> term
    29   val norm_type: Type.tyenv -> typ -> typ
    30   val norm_type_same: Type.tyenv -> typ -> typ
    31   val norm_types_same: Type.tyenv -> typ list -> typ list
    32   val beta_norm: term -> term
    33   val head_norm: env -> term -> term
    34   val fastype: env -> typ list -> term -> typ
    35   val typ_subst_TVars: Type.tyenv -> typ -> typ
    36   val subst_TVars: Type.tyenv -> term -> term
    37   val subst_Vars: tenv -> term -> term
    38   val subst_vars: Type.tyenv * tenv -> term -> term
    39 end;
    40 
    41 structure Envir : ENVIR =
    42 struct
    43 
    44 (*updating can destroy environment in 2 ways!!
    45    (1) variables out of range   (2) circular assignments
    46 *)
    47 type tenv = (typ * term) Vartab.table
    48 
    49 datatype env = Envir of
    50     {maxidx: int,      (*maximum index of vars*)
    51      asol: tenv,       (*table of assignments to Vars*)
    52      iTs: Type.tyenv}  (*table of assignments to TVars*)
    53 
    54 fun type_env (Envir {iTs, ...}) = iTs;
    55 
    56 (*Generate a list of distinct variables.
    57   Increments index to make them distinct from ALL present variables. *)
    58 fun genvars name (Envir{maxidx, asol, iTs}, Ts) : env * term list =
    59   let fun genvs (_, [] : typ list) : term list = []
    60         | genvs (n, [T]) = [ Var((name, maxidx+1), T) ]
    61         | genvs (n, T::Ts) =
    62             Var((name ^ radixstring(26,"a",n), maxidx+1), T)
    63             :: genvs(n+1,Ts)
    64   in  (Envir{maxidx=maxidx+1, asol=asol, iTs=iTs}, genvs (0,Ts))  end;
    65 
    66 (*Generate a variable.*)
    67 fun genvar name (env,T) : env * term =
    68   let val (env',[v]) = genvars name (env,[T])
    69   in  (env',v)  end;
    70 
    71 fun var_clash ixn T T' = raise TYPE ("Variable " ^
    72   quote (Syntax.string_of_vname ixn) ^ " has two distinct types",
    73   [T', T], []);
    74 
    75 fun gen_lookup f asol (xname, T) =
    76   (case Vartab.curried_lookup asol xname of
    77      NONE => NONE
    78    | SOME (U, t) => if f (T, U) then SOME t
    79        else var_clash xname T U);
    80 
    81 (* When dealing with environments produced by matching instead *)
    82 (* of unification, there is no need to chase assigned TVars.   *)
    83 (* In this case, we can simply ignore the type substitution    *)
    84 (* and use = instead of eq_type.                               *)
    85 
    86 fun lookup' (asol, p) = gen_lookup op = asol p;
    87 
    88 fun lookup2 (iTs, asol) p =
    89   if Vartab.is_empty iTs then lookup' (asol, p)
    90   else gen_lookup (Type.eq_type iTs) asol p;
    91 
    92 fun lookup (Envir {asol, iTs, ...}, p) = lookup2 (iTs, asol) p;
    93 
    94 fun update (((xname, T), t), Envir {maxidx, asol, iTs}) =
    95   Envir{maxidx=maxidx, asol=Vartab.curried_update_new (xname, (T, t)) asol, iTs=iTs};
    96 
    97 (*The empty environment.  New variables will start with the given index+1.*)
    98 fun empty m = Envir{maxidx=m, asol=Vartab.empty, iTs=Vartab.empty};
    99 
   100 (*Test for empty environment*)
   101 fun is_empty (Envir {asol, iTs, ...}) = Vartab.is_empty asol andalso Vartab.is_empty iTs;
   102 
   103 (*Determine if the least index updated exceeds lim*)
   104 fun above (lim, Envir {asol, iTs, ...}) =
   105   (case (Vartab.min_key asol, Vartab.min_key iTs) of
   106      (NONE, NONE) => true
   107    | (SOME (_, i), NONE) => i > lim
   108    | (NONE, SOME (_, i')) => i' > lim
   109    | (SOME (_, i), SOME (_, i')) => i > lim andalso i' > lim);
   110 
   111 (*Update, checking Var-Var assignments: try to suppress higher indexes*)
   112 fun vupdate ((aU as (a, U), t), env as Envir {iTs, ...}) = case t of
   113       Var (nT as (name', T)) =>
   114         if a = name' then env     (*cycle!*)
   115         else if xless(a, name')  then
   116            (case lookup (env, nT) of  (*if already assigned, chase*)
   117                 NONE => update ((nT, Var (a, T)), env)
   118               | SOME u => vupdate ((aU, u), env))
   119         else update ((aU, t), env)
   120     | _ => update ((aU, t), env);
   121 
   122 
   123 (*Convert environment to alist*)
   124 fun alist_of (Envir{asol,...}) = Vartab.dest asol;
   125 
   126 
   127 (*** Beta normal form for terms (not eta normal form).
   128      Chases variables in env;  Does not exploit sharing of variable bindings
   129      Does not check types, so could loop. ***)
   130 
   131 (*raised when norm has no effect on a term, to do sharing instead of copying*)
   132 exception SAME;
   133 
   134 fun norm_term1 same (asol,t) : term =
   135   let fun norm (Var wT) =
   136             (case lookup' (asol, wT) of
   137                 SOME u => (norm u handle SAME => u)
   138               | NONE   => raise SAME)
   139         | norm (Abs(a,T,body)) =  Abs(a, T, norm body)
   140         | norm (Abs(_,_,body) $ t) = normh(subst_bound (t, body))
   141         | norm (f $ t) =
   142             ((case norm f of
   143                Abs(_,_,body) => normh(subst_bound (t, body))
   144              | nf => nf $ (norm t handle SAME => t))
   145             handle SAME => f $ norm t)
   146         | norm _ =  raise SAME
   147       and normh t = norm t handle SAME => t
   148   in (if same then norm else normh) t end
   149 
   150 fun normT iTs (Type (a, Ts)) = Type (a, normTs iTs Ts)
   151   | normT iTs (TFree _) = raise SAME
   152   | normT iTs (TVar vS) = (case Type.lookup (iTs, vS) of
   153           SOME U => normTh iTs U
   154         | NONE => raise SAME)
   155 and normTh iTs T = ((normT iTs T) handle SAME => T)
   156 and normTs iTs [] = raise SAME
   157   | normTs iTs (T :: Ts) =
   158       ((normT iTs T :: (normTs iTs Ts handle SAME => Ts))
   159        handle SAME => T :: normTs iTs Ts);
   160 
   161 fun norm_term2 same (asol, iTs, t) : term =
   162   let fun norm (Const (a, T)) = Const(a, normT iTs T)
   163         | norm (Free (a, T)) = Free(a, normT iTs T)
   164         | norm (Var (w, T)) =
   165             (case lookup2 (iTs, asol) (w, T) of
   166                 SOME u => normh u
   167               | NONE   => Var(w, normT iTs T))
   168         | norm (Abs (a, T, body)) =
   169                (Abs (a, normT iTs T, normh body) handle SAME => Abs (a, T, norm body))
   170         | norm (Abs(_, _, body) $ t) = normh (subst_bound (t, body))
   171         | norm (f $ t) =
   172             ((case norm f of
   173                Abs(_, _, body) => normh (subst_bound (t, body))
   174              | nf => nf $ normh t)
   175             handle SAME => f $ norm t)
   176         | norm _ =  raise SAME
   177       and normh t = (norm t) handle SAME => t
   178   in (if same then norm else normh) t end;
   179 
   180 fun gen_norm_term same (env as Envir{asol,iTs,...}) t : term =
   181   if Vartab.is_empty iTs then norm_term1 same (asol, t)
   182   else norm_term2 same (asol, iTs, t);
   183 
   184 val norm_term = gen_norm_term false;
   185 val norm_term_same = gen_norm_term true;
   186 
   187 val beta_norm = norm_term (empty 0);
   188 
   189 fun norm_type iTs = normTh iTs;
   190 fun norm_type_same iTs =
   191   if Vartab.is_empty iTs then raise SAME else normT iTs;
   192 
   193 fun norm_types_same iTs =
   194   if Vartab.is_empty iTs then raise SAME else normTs iTs;
   195 
   196 
   197 (*Put a term into head normal form for unification.*)
   198 
   199 fun head_norm env t =
   200   let
   201     fun hnorm (Var vT) = (case lookup (env, vT) of
   202           SOME u => head_norm env u
   203         | NONE => raise SAME)
   204       | hnorm (Abs (a, T, body)) =  Abs (a, T, hnorm body)
   205       | hnorm (Abs (_, _, body) $ t) =
   206           head_norm env (subst_bound (t, body))
   207       | hnorm (f $ t) = (case hnorm f of
   208           Abs (_, _, body) => head_norm env (subst_bound (t, body))
   209         | nf => nf $ t)
   210 	  | hnorm _ =  raise SAME
   211   in hnorm t handle SAME => t end;
   212 
   213 
   214 (*finds type of term without checking that combinations are consistent
   215   Ts holds types of bound variables*)
   216 fun fastype (Envir {iTs, ...}) =
   217 let val funerr = "fastype: expected function type";
   218     fun fast Ts (f $ u) =
   219 	(case fast Ts f of
   220 	   Type ("fun", [_, T]) => T
   221 	 | TVar ixnS =>
   222 		(case Type.lookup (iTs, ixnS) of
   223 		   SOME (Type ("fun", [_, T])) => T
   224 		 | _ => raise TERM (funerr, [f $ u]))
   225 	 | _ => raise TERM (funerr, [f $ u]))
   226       | fast Ts (Const (_, T)) = T
   227       | fast Ts (Free (_, T)) = T
   228       | fast Ts (Bound i) =
   229 	(List.nth (Ts, i)
   230   	 handle Subscript => raise TERM ("fastype: Bound", [Bound i]))
   231       | fast Ts (Var (_, T)) = T 
   232       | fast Ts (Abs (_, T, u)) = T --> fast (T :: Ts) u
   233 in fast end;
   234 
   235 
   236 (*Substitute for type Vars in a type*)
   237 fun typ_subst_TVars iTs T = if Vartab.is_empty iTs then T else
   238   let fun subst(Type(a, Ts)) = Type(a, map subst Ts)
   239         | subst(T as TFree _) = T
   240         | subst(T as TVar ixnS) =
   241             (case Type.lookup (iTs, ixnS) of NONE => T | SOME(U) => U)
   242   in subst T end;
   243 
   244 (*Substitute for type Vars in a term*)
   245 val subst_TVars = map_term_types o typ_subst_TVars;
   246 
   247 (*Substitute for Vars in a term *)
   248 fun subst_Vars itms t = if Vartab.is_empty itms then t else
   249   let fun subst (v as Var ixnT) = getOpt (lookup' (itms, ixnT), v)
   250         | subst (Abs (a, T, t)) = Abs (a, T, subst t)
   251         | subst (f $ t) = subst f $ subst t
   252         | subst t = t
   253   in subst t end;
   254 
   255 (*Substitute for type/term Vars in a term *)
   256 fun subst_vars (iTs, itms) =
   257   if Vartab.is_empty iTs then subst_Vars itms else
   258   let fun subst (Const (a, T)) = Const(a, typ_subst_TVars iTs T)
   259         | subst (Free (a, T)) = Free (a, typ_subst_TVars iTs T)
   260         | subst (Var (ixn, T)) = (case lookup' (itms, (ixn, T)) of
   261             NONE   => Var (ixn, typ_subst_TVars iTs T)
   262           | SOME t => t)
   263         | subst (b as Bound _) = b
   264         | subst (Abs (a, T, t)) = Abs(a, typ_subst_TVars iTs T, subst t)
   265         | subst (f $ t) = subst f $ subst t
   266   in subst end;
   267 
   268 end;