Scala宏:将部分函数重写为匹配

时间:2014-03-10 18:08:18

标签: scala scala-macros

我想将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]                 ^

等等。

有可能将部分函数调用重写为匹配吗?

1 个答案:

答案 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>)
        };
        ()
      }
    }
  }
}

看起来部分函数合成还添加了一个我们不能按原样重用的默认情况,因为它引用了在综合类中定义的一些合成变量。