29

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?

6
  • 9
    That's a bug. All of the patterns in your last code block should work for single-argument anonymous functions. Follow SI-7803 to get notified when the fix is merged into master Commented Sep 2, 2013 at 12:06
  • 5
    The fix is sitting in the 2.11 pull requests queue. After it's merged I'll backport it to 2.10. I was also a bit wrong with saying that all patterns will work. You'll have to use parentheses over arguments (i.e. patterns 2 and 4) Commented Sep 5, 2013 at 19:23
  • @DenShabalin Should matching against function types work as well? I successfully matched as follows val q"Capture.capture[$tp]" = tree with tree as capture[() => R], capture[A => R], capture[(A, B) => R], etc. Next I am failed to match val tq"(..$ts) => $tr" = tp. Please, give a hint on how it should be done. Commented Sep 27, 2013 at 16:33
  • 3
    @DenShabalin: shouldn't that be an answer? Commented Jan 20, 2014 at 5:50
  • Matching against function literals and functions types should work in 2.11.x but might not work via paradise plugin for 2.10 atm. There is a plan to backport latest quasiquotes to paradise plugin around 2.11 release. Commented Jan 29, 2014 at 14:13

1 Answer 1

8

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.