# Helpers datatype 'a list { Cons ('a, 'a list), Empty, } datatype 'a maybe { Just 'a, Nothing, } # Lambda calculus term, nameless representation datatype term { Var int Int int Abs term App (term, term) } # Result of the evaluation datatype value { Int int Closure (env, term) } alias env = value list typecheck add_binding : value -> env -> env def add_binding v env = Cons v env typecheck lookup : int -> env -> value maybe def lookup _ = Nothing | lookup 0 = Just x | lookup n = lookup (subtract n 1) xs typecheck eval : env -> term -> value def eval e = match lookup idx e { case -> v case -> abort "Variable out of scope" } | eval e = Int x | eval e = Closure e t | eval e = let def new_env = add_binding (eval e t2) e in eval new_env t1