(*
*
* 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