我想将partial function
重写为match
表达式。
//macro and impl
def pfRewrite(pf: PartialFunction[Int, Int]) = macro ResponderImpl.pfRewriteImpl
def pfRewriteImpl(c: Context)(pf: c.Expr[PartialFunction[Int, Int]]) = {
import c.universe._
val cas = pf.tree.collect {
case x: DefDef if x.name.decoded == "applyOrElse" =>
x.collect {
case cq"$x => $y" => cq"""$x => $y"""
}
}.flatten
val sVal = newTermName("someVal")
val rewrite = q"""
$sVal match {
case ..$cas
}
"""
c.Expr(rewrite)
}
在代码中,我得到PartialFunction
并从cases
方法中获取applyOrElse
,然后我为“someVal”创建match
表达式。代码中的这个值:
//test
def test {
val someVal = 10
pfRewrite {
case 1 => 10
case _ => 100
}
}
但我有错误:
[error] found : Int(10)
[error] required: Nothing
[error] case 1 => 10
[error] ^
等等。
有可能将部分函数调用重写为匹配吗?
答案 0 :(得分:1)
通常,这类笨拙的错误消息源于混合类型和非类型化树(有关详细信息,请查看Scala macros: What is the difference between typed (aka typechecked) an untyped Trees)。因此,在我们确定情况之前,在计划与非类型树混合的类型树上执行resetLocalAttrs是一种很好的做法。
此案例也不例外。使用c.resetLocalAttrs(pf.tree)
代替pf.tree
可以揭示宏扩展的真正问题:
12:57 ~/Projects/Master/sandbox (master)$ scalac Test.scala
Test.scala:5: error: not found: value default
Macros.pfRewrite {
^
如果我们启用-Xprint:typer
,这是查看宏扩展的方式之一(以及-Ymacro-debug-lite
和-Ymacro-debug-verbose
),那么我们就会看到了什么' s继续:
[[syntax trees at end of typer]] // Test.scala
package <empty> {
object Test extends AnyRef with App {
def <init>(): Test.type = {
Test.super.<init>();
()
};
def test: Unit = {
val someVal: Int = 10;
{
someVal match {
case 1 => 10
case _ => 100
case (defaultCase$ @ _) => <default: error>.apply(<x1: error>)
};
()
}
}
}
}
看起来部分函数合成还添加了一个我们不能按原样重用的默认情况,因为它引用了在综合类中定义的一些合成变量。