Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching function literals with quasiquotes in Scala

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?

like image 730
Travis Brown Avatar asked Sep 01 '13 15:09

Travis Brown


1 Answers

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.

like image 200
Denys Shabalin Avatar answered Oct 21 '22 02:10

Denys Shabalin