Skip to content

Commit d37b153

Browse files
committed
Add let abstractions with customizable names
1 parent 2dd7c32 commit d37b153

File tree

6 files changed

+103
-13
lines changed

6 files changed

+103
-13
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -583,19 +583,18 @@ val y: scala.Double = y.*(y)
583583
y
584584
```
585585
Even though there is no hygiene issue it may be hard to undestand the code. To overcome this inconvenience
586-
each `y` can be assigned a meaningful name using the `scala.quoted.show.showName` annotation.
587-
For example `'{ @showName(${Expr("y" + i)}) val y = $x * $x; ... }` will assign to each `y` a name
588-
`a{i}` where `{i}` is a known String, if `i == 3` then it would be named `a3`.
586+
each `y` can be assigned a meaningful name using the `scala.quoted.util.let`.
587+
For example `let("y" + i)('{ $x * $x })(yi => ...)` will assign to each `y` a name
588+
`y{i}` where `{i}` is a known String, if `i == 3` then it would be named `y3`.
589589

590590
The `powerCode` can be defined as follows using `showName`
591591
```scala
592-
def powerCodeD(n: Long, x: Expr[Double]))(given QuoteContext): Expr[Double] = '{
593-
val a1 = $x
594-
${ powerCodeD(n, 2, 'x1) }
595-
}
592+
def powerCodeD(n: Long, x: Expr[Double]))(given QuoteContext): Expr[Double] =
593+
let("y1")(x)(y1 => powerCodeD(n, 2, y1))
594+
596595
def powerCodeD(n: Long, i: Int, x: Expr[Double])(given QuoteContext): Expr[Double] =
597596
if (n == 0) '{1.0}
598-
else if (n % 2 == 0) '{ @showName(${Expr("a" + i)}) val y = $x * $x; ${powerCodeD(n / 2, idx * 2, 'y)} }
597+
else if (n % 2 == 0) let("y" + i)('{ $x * $x })(ai => powerCodeD(n / 2, idx * 2, yi) }
599598
else '{ $x * ${powerCodeD(n - 1, idx, x)} }
600599
```
601600
then
@@ -604,11 +603,11 @@ powerCodeD(16, '{7}).show
604603
```
605604
will show
606605
```scala
607-
val a1: scala.Double = 7
608-
val a2: scala.Double = a1.*(a1)
609-
val a4: scala.Double = a2.*(a2)
610-
val a8: scala.Double = a4.*(a4)
611-
val a16: scala.Double = a8.*(a8)
606+
val y1: scala.Double = 7
607+
val y2: scala.Double = y1.*(y1)
608+
val y4: scala.Double = y2.*(y2)
609+
val y8: scala.Double = y4.*(y4)
610+
val y16: scala.Double = y8.*(y8)
612611
a16
613612
```
614613

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package scala.quoted
2+
3+
import scala.internal.quoted.showName
4+
5+
package object util {
6+
7+
/** Genrate the code `'{ val `<name>` = $expr; ${ body('<name>) } }` with the given name */
8+
def let[T: Type, U: Type](name: String)(expr: Expr[T])(body: Expr[T] => Expr[U])(given QuoteContext): Expr[U] = '{
9+
@showName(${Expr(name)}) val x = $expr
10+
${ body('x) }
11+
}
12+
13+
/** Genrate the code `'{ val x$<i> = $expr; ${ body('x$<i>) } }` for a fresh i */
14+
def let[T: Type, U: Type](expr: Expr[T])(body: Expr[T] => Expr[U])(given QuoteContext): Expr[U] =
15+
let("x$" + nextIdx)(expr)(body)
16+
17+
private[util] var lastIdx = 0
18+
private def nextIdx: Int = {
19+
lastIdx += 1
20+
lastIdx
21+
}
22+
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
((x1: scala.Double) => x1.*({
2+
val x$1: scala.Double = x1.*(x1)
3+
val x$2: scala.Double = x$1.*(x$1)
4+
x$2.*({
5+
val x$3: scala.Double = x$2.*(x$2)
6+
x$3.*({
7+
val x$4: scala.Double = x$3.*(x$3)
8+
val x$5: scala.Double = x$4.*(x$4)
9+
val x$6: scala.Double = x$5.*(x$5)
10+
x$6
11+
})
12+
})
13+
}))
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted._
2+
import scala.quoted.util.let
3+
import scala.quoted.staging._
4+
import scala.reflect.ClassTag
5+
6+
object Test {
7+
given Toolbox = Toolbox.make(getClass.getClassLoader)
8+
def main(args: Array[String]): Unit = withQuoteContext {
9+
println(powerCode(77).show)
10+
}
11+
12+
def powerCode(n: Long)(given QuoteContext): Expr[Double => Double] =
13+
'{ x1 => ${powerCode(n, 2, 'x1)} }
14+
15+
def powerCode(n: Long, idx: Int, x: Expr[Double])(given QuoteContext): Expr[Double] =
16+
if (n == 0) '{1.0}
17+
else if (n == 1) x
18+
else if (n % 2 == 0) let('{ $x * $x })(y => powerCode(n / 2, idx * 2, y))
19+
else '{ $x * ${powerCode(n - 1, idx, x)} }
20+
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
((x1: scala.Double) => x1.*({
2+
val x2: scala.Double = x1.*(x1)
3+
val x4: scala.Double = x2.*(x2)
4+
x4.*({
5+
val x8: scala.Double = x4.*(x4)
6+
x8.*({
7+
val x16: scala.Double = x8.*(x8)
8+
val x32: scala.Double = x16.*(x16)
9+
val x64: scala.Double = x32.*(x32)
10+
x64
11+
})
12+
})
13+
}))
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted._
2+
import scala.quoted.util.let
3+
import scala.quoted.staging._
4+
import scala.reflect.ClassTag
5+
6+
object Test {
7+
given Toolbox = Toolbox.make(getClass.getClassLoader)
8+
def main(args: Array[String]): Unit = withQuoteContext {
9+
println(powerCode(77).show)
10+
}
11+
12+
def powerCode(n: Long)(given QuoteContext): Expr[Double => Double] =
13+
'{ x1 => ${powerCode(n, 2, 'x1)} }
14+
15+
def powerCode(n: Long, idx: Int, x: Expr[Double])(given QuoteContext): Expr[Double] =
16+
if (n == 0) '{1.0}
17+
else if (n == 1) x
18+
else if (n % 2 == 0) let(s"x$idx")('{ $x * $x })(y => powerCode(n / 2, idx * 2, y))
19+
else '{ $x * ${powerCode(n - 1, idx, x)} }
20+
21+
}

0 commit comments

Comments
 (0)