You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--Error:ExprMatchingPlayground.scala:13:28---------------------------------------------------------------------------------------------------------------------------------------------------------------13|case'{ ((y: Int) => $f(y)).apply($z: Int) } =>|^|Type must be fully defined.
|Consider annotating the splice using a typeascription:| ($<none>(y):XYZ).
-- [E006] NotFoundError:ExprMatchingPlayground.scala:16:8-----------------------------------------------------------------------------------------------------------------------------------------------16| f(z) // generates '{ 2 + 1 }|^|Notfound: f
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|Explanation (enabled by `-explain`)
|----------------------------------------------------------------------------------------------------|The identifier for `f` is not bound, that is,
| no declaration forthis identifier can be found.
|That can happen, for example, if `f` or its declaration has either been
| misspelt or if an importismissing.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [E006] NotFoundError:ExprMatchingPlayground.scala:16:10----------------------------------------------------------------------------------------------------------------------------------------------16| f(z) // generates '{ 2 + 1 }|^|Notfound: z
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|Explanation (enabled by `-explain`)
|----------------------------------------------------------------------------------------------------|The identifier for `z` is not bound, that is,
| no declaration forthis identifier can be found.
|That can happen, for example, if `z` or its declaration has either been
| misspelt or if an importismissing.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------3 errors found
the pattern case '{ ((y: Int) => $f(y)).apply($z: Int) } should not require further annotations
as implied by the comment // f = (y: Expr[Int]) => '{ $y + 1 }, f should have type Expr[Int] => Expr[Int]
the associated expression f(z) should, as explicitly commented in the reference example, generate '{2 + 1}
and thus f and z must be bound at that point
Further notes
Because this is a reference example, I believe I should not need to add further type annotations to make it compile. However, if I do add further annotations, and helper methods, I find that:
case '{ ((y: Int) => $f(y): Int).apply($z: Int) } is enough to resolve the "Type must be fully defined" error
However, it's implied from the comment and use that f: Expr[Int] => Expr[Int]. I cannot get this to be true; with the annotation above, I havef: Expr[Int => Int]. I cannot find an annotation which I can apply inside the '{...}which lets f: Expr[Int] => Expr[Int]; if there's a different annotation which would give this desire result, please let me know!
for this reason, trying to do f(z), as in the reference, yields an error that f does not take parameters (b/c f is not a function; it is an Expr of a function)
In the comments from the reference example, f(z) has the behavior of returning an expression in which occurrences of y are replaced with z, generating '{2 + 1}. While I see a way to recover an Expr[Int] => Expr[Int] described in the docs in the staged lambdas section, it doesn't allow us to generate '{2 + 1} in this at macro-time. We can create an expression in which the function f expresses is called, and we can beta-reduce the whole output. It seems that the mismatch between f: Expr[Int] => Expr[Int] in the reference vs f: Expr[Int => Int] which I can get to at least compile, meaningfully changes what one can do with the it.
objectExprMatchingPlayground {
inlinedeffoo():Int=${ scrutinizeHoas }
defscrutinizeHoas(usingqctx: Quotes) = {
newHelper(using qctx).scrutinizeHoasHelper()
}
classHelper(usingqctx: Quotes) {
importqctx.reflect.*defnowWithBeta[T:Type, U:Type](f: Expr[T=>U]):Expr[T] =>Expr[U] =
(x: Expr[T]) =>Expr.betaReduce('{ $f($x) })
defnow[T:Type, U:Type](f: Expr[T=>U]):Expr[T] =>Expr[U] =
(x: Expr[T]) =>'{ $f($x) }
defscrutinizeHoasHelper():Expr[Int] = {
// example from https://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html#hoas-patterns-1// see stack overflow question https://stackoverflow.com/questions/77718835/why-does-this-scala-3-macros-reference-example-of-hoas-fail-with-type-must-be-fvalw='{ ((x: Int) => x +1).apply(2) } match {
case'{ ((y: Int) => $f(y):Int).apply($z: Int) } =>// f may contain references to `x` (replaced by `$y`)// f = (y: Expr[Int]) => '{ $y + 1 }
println(s"f = ${f.asTerm.show(usingPrinter.TreeCode)}") // f = ((y: scala.Int) => y.+(1))valg= now[Int, Int](f) // can also use `nowWithBeta`
g(z)
case _ =>'{ 0 }
}
// if we just use `now`, we print `w = ((y: scala.Int) => y.+(1)).apply(2)`// if we use `nowWithBeta`, we just print `w = 3`
println(s"w = ${w.asTerm.show(usingPrinter.TreeCode)}")
w
}
}
}
I am not well-versed in scala 3 or especially in scala 3 macros, and it's possible I've made some error. But how is one to learn, if the material in the official reference do not work as described?
The text was updated successfully, but these errors were encountered:
This example comes from a pre-3.0.0 version of the HOAS pattern. I will update the example. @abeppu, as far as I can tell, your understanding of the system is correct. Just note that now will also beta-reduce, but it will happen after the macro has expanded (in some later optimization phase).
There is also a bug in the error message that needs to be fixed ($<none>(y): XYZ). It should have printed ($f(y): XYZ).
I find that a HOAS pattern matching example in the scala 3 reference does not compile.
The example is here https://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html#hoas-patterns-1
I have wrapped this in a minimal dummy macro as a scaffolding exercise it (providing quotes, etc), and find that it fails.
I originally asked about this on SO, with the assumption that something must be wrong with my setup; the only responder at time of writing also attempted variants on this without success. https://stackoverflow.com/questions/77718835/why-does-this-scala-3-macros-reference-example-of-hoas-fail-with-type-must-be-f?r=SearchResults
Compiler version
3.3.1
(but also reproduced on 3.0.0)
Minimized code
In ExprmatchingPlayground.scala
in ExprMatchingDemo.scala
(see also this gist: https://gist.github.com/abeppu/2fa3af1e2a92c9d2ec666229781d0b20 )
Output
Compiling and using
scalac -explain
I get:Expectation
The pattern matching section here was copy-pasted directly from a reference example: https://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html#hoas-patterns-1
For that reason, as documented, I expect that:
case '{ ((y: Int) => $f(y)).apply($z: Int) }
should not require further annotations// f = (y: Expr[Int]) => '{ $y + 1 }
,f
should have typeExpr[Int] => Expr[Int]
f(z)
should, as explicitly commented in the reference example, generate'{2 + 1}
f
andz
must be bound at that pointFurther notes
Because this is a reference example, I believe I should not need to add further type annotations to make it compile. However, if I do add further annotations, and helper methods, I find that:
case '{ ((y: Int) => $f(y): Int).apply($z: Int) }
is enough to resolve the "Type must be fully defined" errorf: Expr[Int] => Expr[Int]
. I cannot get this to be true; with the annotation above, I havef: Expr[Int => Int]
. I cannot find an annotation which I can apply inside the'{...}
which letsf: Expr[Int] => Expr[Int]
; if there's a different annotation which would give this desire result, please let me know!f(z)
, as in the reference, yields an error thatf does not take parameters
(b/c f is not a function; it is an Expr of a function)f(z)
has the behavior of returning an expression in which occurrences ofy
are replaced withz
, generating'{2 + 1}
. While I see a way to recover anExpr[Int] => Expr[Int]
described in the docs in the staged lambdas section, it doesn't allow us to generate'{2 + 1}
in this at macro-time. We can create an expression in which the functionf
expresses is called, and we can beta-reduce the whole output. It seems that the mismatch betweenf: Expr[Int] => Expr[Int]
in the reference vsf: Expr[Int => Int]
which I can get to at least compile, meaningfully changes what one can do with the it.I am not well-versed in scala 3 or especially in scala 3 macros, and it's possible I've made some error. But how is one to learn, if the material in the official reference do not work as described?
The text was updated successfully, but these errors were encountered: