【问题标题】:Matching function literals with quasiquotes in Scala在 Scala 中将函数文字与准引号匹配
【发布时间】:2013-09-04 18:48:45
【问题描述】:

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

我可以很容易地在函数文字上进行模式匹配,而无需使用准引号:

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()

现在假设我想使用准引号更灵活地进行同一种匹配。以下内容也将匹配该函数,并打印我们期望的内容。

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

是否可以在使用准引号匹配函数字面量时指定参数的类型,或者匹配未知数量的参数?

【问题讨论】:

  • 这是一个错误。最后一个代码块中的所有模式都应该适用于单参数匿名函数。关注 SI-7803 以在修复合并到 master 时收到通知
  • @DenShabalin:谢谢!
  • 修复位于 2.11 拉取请求队列中。合并后,我会将其反向移植到 2.10。我说所有模式都会起作用也有点错误。您必须在参数上使用括号(即模式 2 和 4)
  • @DenShabalin 是否也应该对函数类型进行匹配?我成功匹配如下val q"Capture.capture[$tp]" = tree 与树为capture[() => R]capture[A => R]capture[(A, B) => R] 等。接下来我无法匹配val tq"(..$ts) => $tr" = tp。请给出如何完成的提示。
  • @DenShabalin:这不应该是一个答案吗?

标签: scala macros scala-macros scala-quasiquotes


【解决方案1】:

使用 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 中阅读有关使用准引号处理函数树的更多信息。

【讨论】:

    猜你喜欢
    • 2019-04-24
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 2019-06-24
    • 2012-08-13
    • 2015-07-30
    相关资源
    最近更新 更多