Boolean) extends Exp[Env, Boolean] case V[Env, T](v: Var[Env, T]) extends Exp[Env, T] case L[Env, A, B](f: Exp[(A, Env), B]) extends Exp[Env, A => B] case A[Env, A, B]( f: Exp[Env, A => B], e: Exp[Env, A]) extends Exp[Env, B] enum Var[Env, T]: case VZ[Env, T]() extends Var[(T, Env), T] case VS[Env, A, T](v: Var[Env, T]) extends Var[(A, Env), T] • The GADT is not only parameterized with the type of the object term but also with the environment, i.e. the free variables in the term • Constructors express the type system of the calculus, e.g. booleans have the type Boolean in any Env, the application of A => B to A gives you B all in the same Env, etc