Scala quasiquote concatenation
Asked Answered
O

1

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.

Outrider answered 20/5, 2015 at 7:42 Comment(8)
I believe this is correct approach. What error you have exactly?Parabolic
Also your pattern is bit strange x => 1 mathes any expression, if you are referencing to some local value named x you should use `x` => 1 as paternParabolic
The error is the following: exception during macro expansion: java.lang.IllegalArgumentException: scala.collection.immutable.List(case (x @ _) => 1, case _ => 0) is not valid representation of pattern match case.Outrider
Are you using Scala 2.10 or 2.11?Gaselier
My pattern doesn't make any sense now, I just took something very simple.Outrider
Scala version is 2.11Outrider
And it works if I write like this: val case1 = cq"x => 1 " val case2 = cq"_ => 0 " val tree = q""" { case $case1 case $case2 } """Outrider
Can you please provide more details. I can't really reproduce the issue on 2.11.6. gist.github.com/densh/377df69df170fa205f3bGaselier
N
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.

Nobody answered 20/5, 2015 at 13:49 Comment(2)
Pattern matching anon funcs can be Function or PartialFunction depending on the expected type.Quickfreeze
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]Cassidycassie

© 2022 - 2024 — McMap. All rights reserved.