(* * * BU CAS CS 520, F2002 * Assignment 2 * *) (* The code was written by Hongwei Xi on 3 Oct 2002 *) signature EVALUATOR = sig datatype term0 = TmVar0 of string | TmLam0 of string * term0 | TmApp0 of term0 * term0 val evaluate: term0 -> term0 end structure Evaluator :> EVALUATOR = struct datatype term0 = TmVar0 of string | TmLam0 of string * term0 | TmApp0 of term0 * term0 (* 'isClosed' tests whether a term is closed *) fun isClosed (t: term0): bool = let fun aux (env: string list, t: term0) = case t of TmVar0 x => List.exists (fn x' => x = x') env | TmLam0 (x, t) => aux (x :: env, t) | TmApp0 (t1, t2) => aux (env, t1) andalso aux (env, t2) in aux ([], t) end (* the usual substitution function on terms *) fun subst (x: string, t1: term0, t2: term0): term0 = case t2 of TmVar0 x' => if x = x' then t1 else t2 | TmLam0 (x', t2') => if x = x' then t2 else TmLam0 (x', subst (x, t1, t2')) | TmApp0 (t21, t22) => TmApp0 (subst (x, t1, t21), subst (x, t1, t22)) exception Impossible exception UnboundVariable (* 'eval' should only be applied to closed terms *) fun eval (t: term0): term0 = case t of TmVar0 _ => raise UnboundVariable | TmLam0 _ => t | TmApp0 (t1, t2) => let val t1 = eval t1 val t2 = eval t2 in case t1 of TmLam0 (x, t1') => eval (subst (x, t2, t1')) | _ => raise Impossible end exception TermIsNotClosed fun evaluate (t: term0): term0 = if isClosed t then eval t else raise TermIsNotClosed end