1

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?

Community
  • 1
  • 1
Marc Grue
  • 5,865
  • 3
  • 16
  • 23
  • What should `q"new Validator($predicate)"` produce? Do you want a reference to the name `predicate`, or do you want an AST of the underlying function? – Eugene Burmako Apr 22 '14 at 18:49
  • I want to pass predicates to verify user input later with them. So I could probably have simplified the example to just `Seq[T](predicate: T => Boolean)` I guess. Or do you have using c.prefix in mind? Thanks for your help. – Marc Grue Apr 22 '14 at 22:56
  • Hmm sorry still not quite sure what you mean. Could you explain what code do you want `q"new Validator($predicate)"` to generate? – Eugene Burmako Apr 23 '14 at 08:25
  • I updated the question, does that make it clearer what I want to do or maybe how I'm approaching this in a wrong way? Thanks. – Marc Grue Apr 24 '14 at 01:37

1 Answers1

3

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.

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59
  • Thank you Eugene! That should solve my problem. I'm traveling now but will hopefully get a chance to implement your solution soon. – Marc Grue Apr 25 '14 at 07:45