Подтвердить что ты не робот

Соответствующие литералы функций с квазикварталами в Scala

Этот вопрос похож по мотивам моего предыдущего вопроса (хотя он касается проблемы, с которой я столкнулся в другой контекст).

Я могу легко сопоставлять совпадение в литерале функции без квазиквадратов:

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

Можно ли указать тип параметра при сопоставлении в литерале функции с квазикварталами или совпадение по неизвестному числу параметров?

4b9b3361

Ответ 1

С последним райским плагином для 2.10 и в vanilla 2.11 вы можете сделать это следующим образом:

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

Я только что проверил его с проектом примера рая со следующими 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)
}

Подробнее о обработке деревьев функций с квазикварталами вы можете прочитать в соответствующей главе руководства по квазикварталу.