Frage

This question is similar in motivation to my previous question (although it's about a problem I ran into in a different context).

I can pattern match on a function literal pretty easily without 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
  }
}

Which works like this:

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

Now suppose I want to use quasiquotes to do the same kind of match more flexibly. The following will also match on that function, and prints what we'd expect.

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

But if I want to specify the type in the pattern, it doesn't match:

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

And none of the following even compile:

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

Is it possible to specify the type of a parameter when matching on a function literal with quasiquotes, or to match on an unknown number of parameters?

War es hilfreich?

Lösung

With latest paradise plugin for 2.10 and in vanilla 2.11 you can do it this way:

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

I've just tested it out with paradise example project with following 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"()")
  }
}

And Test.scala:

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

You can read in more about handling of function trees with quasiquotes in corresponding chapter of quasiquote guide.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top