-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to beta reduce curried function applications in quotes reflect
Previously, the curried functions with multiple applications were not able to be beta-reduced in any way, which was unexpected. Now we allow reducing any number of top-level function applications for a curried function. This was also made clearer in the documentation for the affected (Expr.betaReduce and Term.betaReduce) methods.
- Loading branch information
Showing
5 changed files
with
183 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
class Foo | ||
class Bar | ||
class Baz | ||
|
||
import scala.quoted._ | ||
|
||
def assertBetaReduction(using Quotes)(applied: Expr[Any], expected: String): quotes.reflect.Term = | ||
import quotes.reflect._ | ||
val reducedMaybe = Term.betaReduce(applied.asTerm) | ||
assert(reducedMaybe.isDefined) | ||
val reduced = reducedMaybe.get | ||
assert(reduced.show == expected,s"obtained: ${reduced.show}, expected: ${expected}") | ||
reduced | ||
|
||
inline def regularCurriedCtxFun2BetaReduceTest(inline f: Foo ?=> Bar ?=> Int): Unit = | ||
${regularCurriedCtxFun2BetaReduceTestImpl('f)} | ||
def regularCurriedCtxFun2BetaReduceTestImpl(f: Expr[Foo ?=> Bar ?=> Int])(using Quotes): Expr[Int] = | ||
val expected = | ||
"""|{ | ||
| val contextual$3: Bar = new Bar() | ||
| val contextual$2: Foo = new Foo() | ||
| 123 | ||
|}""".stripMargin | ||
val applied = '{$f(using new Foo())(using new Bar())} | ||
assertBetaReduction(applied, expected).asExprOf[Int] | ||
|
||
inline def regularCurriedFun2BetaReduceTest(inline f: Foo => Bar => Int): Int = | ||
${regularCurriedFun2BetaReduceTestImpl('f)} | ||
def regularCurriedFun2BetaReduceTestImpl(f: Expr[Foo => Bar => Int])(using Quotes): Expr[Int] = | ||
val expected = | ||
"""|{ | ||
| val b: Bar = new Bar() | ||
| val f: Foo = new Foo() | ||
| 123 | ||
|}""".stripMargin | ||
val applied = '{$f(new Foo())(new Bar())} | ||
assertBetaReduction(applied, expected).asExprOf[Int] | ||
|
||
inline def typeParamCurriedFun2BetaReduceTest(inline f: [A] => A => [B] => B => Unit): Unit = | ||
${typeParamCurriedFun2BetaReduceTestImpl('f)} | ||
def typeParamCurriedFun2BetaReduceTestImpl(f: Expr[[A] => (a: A) => [B] => (b: B) => Unit])(using Quotes): Expr[Unit] = | ||
val expected = | ||
"""|{ | ||
| type Y = Bar | ||
| val y: Bar = new Bar() | ||
| type X = Foo | ||
| val x: Foo = new Foo() | ||
| typeParamFun2[Y, X](y, x) | ||
|}""".stripMargin | ||
val applied = '{$f.apply[Foo](new Foo()).apply[Bar](new Bar())} | ||
assertBetaReduction(applied, expected).asExprOf[Unit] | ||
|
||
inline def regularCurriedFun3BetaReduceTest(inline f: Foo => Bar => Baz => Int): Int = | ||
${regularCurriedFun3BetaReduceTestImpl('f)} | ||
def regularCurriedFun3BetaReduceTestImpl(f: Expr[Foo => Bar => Baz => Int])(using Quotes): Expr[Int] = | ||
val expected = | ||
"""|{ | ||
| val i: Baz = new Baz() | ||
| val b: Bar = new Bar() | ||
| val f: Foo = new Foo() | ||
| 123 | ||
|}""".stripMargin | ||
val applied = '{$f(new Foo())(new Bar())(new Baz())} | ||
assertBetaReduction(applied, expected).asExprOf[Int] | ||
|
||
inline def typeParamCurriedFun3BetaReduceTest(inline f: [A] => A => [B] => B => [C] => C => Unit): Unit = | ||
${typeParamCurriedFun3BetaReduceTestImpl('f)} | ||
def typeParamCurriedFun3BetaReduceTestImpl(f: Expr[[A] => A => [B] => B => [C] => C => Unit])(using Quotes): Expr[Unit] = | ||
val expected = | ||
"""|{ | ||
| type Z = Baz | ||
| val z: Baz = new Baz() | ||
| type Y = Bar | ||
| val y: Bar = new Bar() | ||
| type X = Foo | ||
| val x: Foo = new Foo() | ||
| typeParamFun3[Z, Y, X](z, y, x) | ||
|}""".stripMargin | ||
val applied = '{$f.apply[Foo](new Foo()).apply[Bar](new Bar()).apply[Baz](new Baz())} | ||
assertBetaReduction(applied, expected).asExprOf[Unit] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
@main def run() = | ||
def typeParamFun2[A, B](a: A, b: B): Unit = println(a.toString + " " + b.toString) | ||
def typeParamFun3[A, B, C](a: A, b: B, c: C): Unit = println(a.toString + " " + b.toString) | ||
|
||
regularCurriedCtxFun2BetaReduceTest((f: Foo) ?=> (b: Bar) ?=> 123) | ||
regularCurriedCtxFun2BetaReduceTest(123) | ||
regularCurriedFun2BetaReduceTest(((f: Foo) => (b: Bar) => 123)) | ||
typeParamCurriedFun2BetaReduceTest([X] => (x: X) => [Y] => (y: Y) => typeParamFun2[Y, X](y, x)) | ||
|
||
regularCurriedFun3BetaReduceTest((f: Foo) => (b: Bar) => (i: Baz) => 123) | ||
typeParamCurriedFun3BetaReduceTest([X] => (x: X) => [Y] => (y: Y) => [Z] => (z: Z) => typeParamFun3[Z, Y, X](z, y, x)) |