10

I'm new to scala macros and I spent a couple of days trying to write my very first one. I have a problem with quasiquotes concatenation.

There is a list of case clauses, let's say the following:

val cases = cq"x => 1 " :: cq"_ => 0 " :: Nil

And I need to build a partial function from it. The problem is that I don't have an idea how to paste them in the final quasiquote. The documentation says I should do something like this:

q"{ case ..$cases }"

but it doesn't work if I do so.

Is there a way to build a PartialFunction from such a list?

Thanks for any help.

1 Answers1

5

The following works for me with 2.11.2:

import scala.reflect.macros.Context
object Macros {
    def partial: PartialFunction[Int, Int] = macro partialImpl
    def partialImpl(c: Context): c.Expr[PartialFunction[Int, Int]]= {
        import c.universe._
        val cases = cq"x => 1 " :: cq"_ => 0 " :: Nil
        val pf = q"{ case ..$cases } : PartialFunction[Int, Int]"
        c.Expr[PartialFunction[Int, Int]](pf)

    }
}

Then you can call Macros.partial(1), for example, or Macros.partial.isDefinedAt(2).

Note that in order to make this work, I had to explicitly use PartialFunction[Int, Int] in the quasiquote q"{ case ..$cases } : PartialFunction[Int, Int]". It didn't work without the explicit type definition (it otherwise assumes PartialFunction[Any, Int]).

Here is the specification for quasiquote Syntax for partial functions. It works as a pure syntax tree, but apparently cannot be interpreted as a typed expression except PartialFunction[Any, T] by a macro unless the type is made explicit.

Ben Reich
  • 16,222
  • 2
  • 38
  • 59
  • Pattern matching anon funcs can be Function or PartialFunction depending on the expected type. – som-snytt May 20 '15 at 16:15
  • Your code has a bug: `PartialFunction[Int, Int]{ case ... }` will create a PartialFunction that is defined on the whole domain. What you want is instead `{ case ... }: PartialFunction[Int, Int]` – Régis Jean-Gilles May 20 '15 at 16:46