From fc584633aa932db6614bc96f02781bfc84f18c9f Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Sun, 4 Mar 2018 21:54:03 +0100 Subject: [PATCH 1/3] Add test to close #3666 --- tests/pos/i3666.scala | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/pos/i3666.scala diff --git a/tests/pos/i3666.scala b/tests/pos/i3666.scala new file mode 100644 index 000000000000..2ef0ecf72430 --- /dev/null +++ b/tests/pos/i3666.scala @@ -0,0 +1,42 @@ +object i3666 { + sealed trait Exp[T] + case class Num(n: Int) extends Exp[Int] + case class Plus(e1: Exp[Int], e2: Exp[Int]) extends Exp[Int] + case class Var[T](name: String) extends Exp[T] + case class Lambda[T, U](x: Var[T], e: Exp[U]) extends Exp[T => U] + case class App[T, U](f: Exp[T => U], e: Exp[T]) extends Exp[U] + + abstract class Env { outer => + def apply[T](x: Var[T]): T + + def + [T](xe: (Var[T], T)) = new Env { + def apply[T](x: Var[T]): T = + if (x == xe._1) xe._2.asInstanceOf[T] + else outer(x) + } + } + + object Env { + val empty = new Env { + def apply[T](x: Var[T]): T = ??? + } + } + + object Test { + + val exp = App(Lambda(Var[Int]("x"), Plus(Var[Int]("x"), Num(1))), Var[Int]("2")) + + def eval[T](e: Exp[T])(env: Env): T = e match { + case Num(n) => n + case Plus(e1, e2) => eval(e1)(env) + eval(e2)(env) + //case v: Var[T] => env(v) + case v: Var[_] => + val w: Var[Nothing] = w + env(v) + case Lambda(x: Var[s], e) => ((y: s) => eval(e)(env + (x -> y))) + case App(f, e) => eval(f)(env)(eval(e)(env)) + } + + eval(exp)(Env.empty) + } +} From de1b90c2563b6eed3ce96cba607b114a4e514e89 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Sun, 4 Mar 2018 21:57:55 +0100 Subject: [PATCH 2/3] Fix leftovers --- tests/pos/i3666.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/pos/i3666.scala b/tests/pos/i3666.scala index 2ef0ecf72430..d6bf7e98403a 100644 --- a/tests/pos/i3666.scala +++ b/tests/pos/i3666.scala @@ -29,9 +29,7 @@ object i3666 { def eval[T](e: Exp[T])(env: Env): T = e match { case Num(n) => n case Plus(e1, e2) => eval(e1)(env) + eval(e2)(env) - //case v: Var[T] => env(v) case v: Var[_] => - val w: Var[Nothing] = w env(v) case Lambda(x: Var[s], e) => ((y: s) => eval(e)(env + (x -> y))) case App(f, e) => eval(f)(env)(eval(e)(env)) From f37f20840d0694803ff0dcfbaa751be3ff3b4cda Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Sun, 4 Mar 2018 21:58:05 +0100 Subject: [PATCH 3/3] Add testcase using HOAS interpreter --- tests/pos/i3666.scala | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/pos/i3666.scala b/tests/pos/i3666.scala index d6bf7e98403a..f42e1f7f4350 100644 --- a/tests/pos/i3666.scala +++ b/tests/pos/i3666.scala @@ -38,3 +38,29 @@ object i3666 { eval(exp)(Env.empty) } } +// A HOAS well-typed interpreter +object i3666Hoas { + sealed trait Exp[T] + case class IntLit(n: Int) extends Exp[Int] + case class BooleanLit(b: Boolean) extends Exp[Boolean] + + case class GenLit[T](t: T) extends Exp[T] + case class Plus(e1: Exp[Int], e2: Exp[Int]) extends Exp[Int] + case class Fun[S, T](f: Exp[S] => Exp[T]) extends Exp[S => T] + case class App[T, U](f: Exp[T => U], e: Exp[T]) extends Exp[U] + + + def eval[T](e: Exp[T]): T = e match { + case IntLit(n) => n + case BooleanLit(b) => b + case GenLit(t) => t + case Plus(e1, e2) => eval(e1) + eval(e2) + case f: Fun[s, t] => + (v: s) => eval(f.f(GenLit(v))) + case App(f, e) => eval(f)(eval(e)) + } + + val exp = App(Fun[S = Int](x => Plus(x, IntLit(1))), IntLit(2)) + + eval(exp) +}