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)
+}