Question

Is there a way to make a Liftable for a functional literal (with 2.11)? If I have

case class Validator[T](predicate: T => Boolean)
val predicate = (s: String) => s.startsWith("Hi")

then I want to be able to quasiquote predicate too:

q"new Validator($predicate)"

I hoped to magically create a Liftable with an underscore. But that was a little too optimistic:

implicit def liftPredicate[T: Liftable](f: T => Boolean) = 
  Liftable[T => Boolean]{ f => q"$f(_)" }

I couldn't figure out from looking at StandardLiftables how I could solve this one.

Another way of looking at it:

Say I want to create instances from the following class at compile time with a macro:

abstract class ClassWithValidation {
  val predicate: String => Boolean
  def validate(s: String) = predicate(s)
}

and I retrieve a functional literal from somewhere else as a variable value:

val predicate = (s: String) => s.startsWith("Hi")

Then I want to simply quasiquote that variable into the construction:

q"""new ClassWithValidation {
      val predicate = $predicate
      // other stuff...
    }"""

But it gives me this error:

Error:(46, 28) Can't unquote String => Boolean, consider providing an 
implicit instance of Liftable[String => Boolean]

Normally I can just make such implicit Liftable for a custom type. But I haven't found a way doing the same for a functional literal. Is there a way to do this or do I need to look at it another way?

Was it helpful?

Solution

From what I understand, you're trying to go from a function to an abstract syntax tree that represents its source code (so that it can be spliced into a macro expansion). This is a frequent thing that people request (e.g. it comes up often in DSLs), but there's no straightforward way of achieving that in our current macro system.

What you can do about this at the moment is to save the AST explicitly when declaring a function and then load and use it in your macro. The most convenient way of doing this is via another macro: https://gist.github.com/xeno-by/4542402. One could also imagine writing a macro annotation that would work along the same lines.

In Project Palladium, there is a plan to save typechecked trees for every program being compiled. This means that there will most likely be a straightforward API, e.g. treeOf(predicate) that would automatically return abstract syntax tree comprising the source of the predicate. But that's definitely not something set in stone - we'll see how it goes, and I'll report back on the progress during this year's ScalaDays.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top