Skip to content

Commit 4c842b5

Browse files
committed
Update macros.md
1 parent 1c25381 commit 4c842b5

File tree

1 file changed

+53
-28
lines changed
  • docs/_docs/reference/metaprogramming

1 file changed

+53
-28
lines changed

docs/_docs/reference/metaprogramming/macros.md

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -170,17 +170,10 @@ describing a function into a function mapping trees to trees.
170170
```scala
171171
object Expr:
172172
...
173-
def betaReduce[...](...)(...): ... = ...
173+
def betaReduce[T](expr: Expr[T])(using Quotes): Expr[T]
174174
```
175175

176-
The definition of `Expr.betaReduce(f)(x)` is assumed to be functionally the same as
177-
`'{($f)($x)}`, however it should optimize this call by returning the
178-
result of beta-reducing `f(x)` if `f` is a known lambda expression.
179-
`Expr.betaReduce` distributes applications of `Expr` over function arrows:
180-
181-
```scala
182-
Expr.betaReduce(_): Expr[(T1, ..., Tn) => R] => ((Expr[T1], ..., Expr[Tn]) => Expr[R])
183-
```
176+
`Expr.betaReduce` returns an expression that is functionally equivalent to e, however if e is of the form `((y1, ..., yn) => e2)(e1, ..., en)` then it optimizes the top most call by returning the result of beta-reducing the application. Otherwise returns expr.
184177

185178
## Lifting Types
186179

@@ -192,7 +185,7 @@ quote but no splice between the parameter binding of `T` and its
192185
usage. But the code can be rewritten by adding an explicit binding of a `Type[T]`:
193186

194187
```scala
195-
def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T])(using Type[R], Quotes): Expr[T => R] =
188+
def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R])(using Quotes): Expr[T => R] =
196189
'{ (x: t.Underlying) => ${ f('x) } }
197190
```
198191

@@ -217,14 +210,13 @@ would be rewritten to
217210
```scala
218211
def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R])(using Quotes): Expr[T => R] =
219212
'{
220-
type T = t.Underlying
213+
type T = summon[Type[T]].Underlying
221214
(x: T) => ${ f('x) }
222215
}
223216
```
224217

225-
The `summon` query succeeds because there is a given instance of
226-
type `Type[T]` available (namely the given parameter corresponding
227-
to the context bound `: Type`), and the reference to that value is
218+
The `summon` query succeeds because there is a using parameter of
219+
type `Type[T]`, and the reference to that value is
228220
phase-correct. If that was not the case, the phase inconsistency for
229221
`T` would be reported as an error.
230222

@@ -526,8 +518,8 @@ the code it runs produces one.
526518

527519
## Example Expansion
528520

529-
Assume we have two methods, one `map` that takes an `Expr[Array[T]]` and a
530-
function `f` and one `sum` that performs a sum by delegating to `map`.
521+
Assume we have two methods, `map` that takes an `Expr[Array[T]]` and a
522+
function `f`, and `sum` that performs a sum by delegating to `map`.
531523

532524
```scala
533525
object Macros:
@@ -552,38 +544,66 @@ object Macros:
552544
end Macros
553545
```
554546

555-
A call to `sum_m(Array(1,2,3))` will first inline `sum_m`:
547+
A call to `sum_m(Array(1, 2, 3))` will first inline `sum_m`:
556548

557549
```scala
558-
val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*)
559-
${_root_.Macros.sum('arr)}
550+
val arr: Array[Int] = Array.apply(1, 2, 3)
551+
${ _root_.Macros.sum('arr) }
560552
```
561553

562-
then it will splice `sum`:
554+
then it will call `sum`:
563555

564556
```scala
565-
val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*)
557+
val arr: Array[Int] = Array.apply(1, 2, 3)
558+
${ '{
559+
var sum = 0
560+
${ map('arr, x => '{sum += $x}) }
561+
sum
562+
} }
563+
```
564+
565+
and cancel the `${'{...}}`:
566+
567+
```scala
568+
val arr: Array[Int] = Array.apply(1, 2, 3)
566569

567570
var sum = 0
568571
${ map('arr, x => '{sum += $x}) }
569572
sum
570573
```
571574

572-
then it will inline `map`:
575+
then it will extract `x => '{sum += $x}` into `f`, to have a value:
573576

574577
```scala
575-
val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*)
578+
val arr: Array[Int] = Array.apply(1, 2, 3)
576579

577580
var sum = 0
578581
val f = x => '{sum += $x}
579-
${ _root_.Macros.map('arr, 'f)(Type.of[Int])}
582+
${ _root_.Macros.map('arr, 'f)(Type.of[Int]) }
580583
sum
581584
```
582585

583-
then it will expand and splice inside quotes `map`:
586+
and then call `map`:
584587

585588
```scala
586-
val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*)
589+
val arr: Array[Int] = Array.apply(1, 2, 3)
590+
591+
var sum = 0
592+
val f = x => '{sum += $x}
593+
${ '{
594+
var i: Int = 0
595+
while i < arr.length do
596+
val element: Int = (arr)(i)
597+
sum += element
598+
i += 1
599+
sum
600+
} }
601+
```
602+
603+
and cancel the `${'{...}}` again:
604+
605+
```scala
606+
val arr: Array[Int] = Array.apply(1, 2, 3)
587607

588608
var sum = 0
589609
val f = x => '{sum += $x}
@@ -598,7 +618,7 @@ sum
598618
Finally cleanups and dead code elimination:
599619

600620
```scala
601-
val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*)
621+
val arr: Array[Int] = Array.apply(1, 2, 3)
602622
var sum = 0
603623
var i: Int = 0
604624
while i < arr.length do
@@ -662,7 +682,7 @@ It is possible to deconstruct or extract values out of `Expr` using pattern matc
662682

663683
`scala.quoted` contains objects that can help extracting values from `Expr`.
664684

665-
- `scala.quoted.Expr`/`scala.quoted.Exprs`: matches an expression of a value (or list of values) and returns the value (or list of values).
685+
- `scala.quoted.Expr`/`scala.quoted.Exprs`: matches an expression of a value (resp. list of values) and returns the value (resp. list of values).
666686
- `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Expr`/`Exprs` but only works on primitive values.
667687
- `scala.quoted.Varargs`: matches an explicit sequence of expressions and returns them. These sequences are useful to get individual `Expr[T]` out of a varargs expression of type `Expr[Seq[T]]`.
668688

@@ -682,6 +702,11 @@ private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] =
682702
dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg })
683703
case _ =>
684704
'{ $argsExpr.sum }
705+
706+
sum(1, 2, 3) // gets matched by Varargs
707+
708+
val xs = List(1, 2, 3)
709+
sum(xs*) // doesn't get matched by Varargs
685710
```
686711

687712
### Quoted patterns

0 commit comments

Comments
 (0)