Skip to content

Commit 7faf6f2

Browse files
authored
Merge pull request #8524 from dotty-staging/macro-docs-improvement
Macro docs: explain basic function concepts before explaining β-reduce
2 parents a2354a8 + 6c7ca51 commit 7faf6f2

File tree

1 file changed

+27
-11
lines changed

1 file changed

+27
-11
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,33 @@ expressiveness.
135135

136136
### From `Expr`s to Functions and Back
137137

138-
The `Expr` companion object contains a `betaReduce` conversion that turns a tree
138+
It is possible to convert any `Expr[T => R]` into `Expr[T] => Expr[R]` and back.
139+
These conversions can be implemented as follows:
140+
141+
```scala
142+
def to[T, R](f: Expr[T] => Expr[R])(using QuoteContext): Expr[T => R] =
143+
'{ (x: T) => ${ f('x) } }
144+
145+
def from[T, R](f: Expr[T => R])(using QuoteContext): Expr[T] => Expr[R] =
146+
(x: Expr[T]) => '{ $f($x) }
147+
```
148+
149+
Note how the fundamental phase consistency principle works in two
150+
different directions here for `f` and `x`. In the method `to`, the reference to `f` is
151+
legal because it is quoted, then spliced, whereas the reference to `x`
152+
is legal because it is spliced, then quoted.
153+
154+
They can be used as follows:
155+
156+
```scala
157+
val f1: Expr[Int => String] = to((x: Expr[Int]) => '{ $x.toString }) // '{ (x: Int) => x.toString }
158+
159+
val f2: Expr[Int] => Expr[String] = from('{ (x: Int) => x.toString }) // (x: Expr[Int]) => '{ ((x: Int) => x.toString)($x) }
160+
f2('{2}) // '{ ((x: Int) => x.toString)(2) }
161+
```
162+
163+
One limitation of `from` is that it does not β-reduce when a lambda is called immediately, as evidenced in the code `{ ((x: Int) => x.toString)(2) }`.
164+
In some cases we want to remove the lambda from the code, for this we provide the method `Expr.betaReduce` that turns a tree
139165
describing a function into a function mapping trees to trees.
140166
```scala
141167
object Expr {
@@ -150,16 +176,6 @@ result of beta-reducing `f(x)` if `f` is a known lambda expression.
150176
```scala
151177
Expr.betaReduce(_): Expr[(T1, ..., Tn) => R] => ((Expr[T1], ..., Expr[Tn]) => Expr[R])
152178
```
153-
Its dual, let’s call it `reflect`, can be defined as follows:
154-
```scala
155-
def reflect[T, U](f: Expr[T] => Expr[U]): Expr[T => U] = '{
156-
(x: T) => ${ f('x) }
157-
}
158-
```
159-
Note how the fundamental phase consistency principle works in two
160-
different directions here for `f` and `x`. The reference to `f` is
161-
legal because it is quoted, then spliced, whereas the reference to `x`
162-
is legal because it is spliced, then quoted.
163179

164180
### Lifting Types
165181

0 commit comments

Comments
 (0)