在Scala中匹配函数文字与quasiquotes

时间:2013-09-01 15:40:49

标签: scala macros scala-macros scala-quasiquotes

这个问题与我previous question的动机相似(虽然它是关于我在different context遇到的问题)。

我可以在没有quasiquotes的情况下轻松地在函数文字上进行模式匹配:

import scala.reflect.macros.Context
import scala.language.experimental.macros

object QQExample {
  def funcDemo(f: Int => String) = macro funcDemo_impl
  def funcDemo_impl(c: Context)(f: c.Expr[Int => String]) = {
    import c.universe._

    f.tree match {
      case Function(ps, body) => List(ps, body) foreach println
      case _ => c.abort(
        c.enclosingPosition,
        "Must provide a function literal."
      )
    }

    c.literalUnit
  }
}

其中的工作原理如下:

scala> QQExample.funcDemo((a: Int) => a.toString)
List(val a: Int = _)
a.toString()

现在假设我想使用quasiquotes更灵活地进行相同类型的匹配。以下内容也将与该功能相匹配,并打印出我们期望的内容。

case q"($x: $t) => $body" => List(x, t, body) foreach println

但是如果我想在模式中指定类型,它就不匹配:

case q"($x: Int) => $body" => List(x, body) foreach println

以下都没有编译:

case q"$p => $body"      => List(p,  body) foreach println
case q"($p) => $body"    => List(p,  body) foreach println
case q"..$ps => $body"   => List(ps, body) foreach println
case q"(..$ps) => $body" => List(ps, body) foreach println

当使用quasiquotes匹配函数文本时,是否可以指定参数的类型,或者匹配未知数量的参数?

1 个答案:

答案 0 :(得分:6)

使用2.10的最新天堂插件和香草2.11,您可以这样做:

val q"(..$args) => $body" = f.tree

我刚刚使用paradise example project测试了Macros.scala

import language.experimental.macros
import scala.reflect.macros.Context

object Macro {
  def apply(f: Any): Any = macro impl
  def impl(c: Context)(f: c.Expr[Any]) = { import c.universe._
    val q"(..$args) => $body" = f.tree
    println(s"args = $args, body = $body")
    c.Expr(q"()")
  }
}

Test.scala

object Test extends App {
  Macro((x: Int) => x + 1)
}

您可以在corresponding chapter of quasiquote guide中阅读有关使用quasiquotes处理函数树的更多信息。