功能文字可升级

时间:2014-04-22 11:38:22

标签: scala-macros scala-quasiquotes

有没有办法为功能性文字制作Liftable(2.11)?如果我有

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

然后我希望能够引用predicate

q"new Validator($predicate)"

我希望用下划线神奇地创造一个Liftable。但这有点过于乐观了:

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

我无法从StandardLiftables看出如何解决这个问题。

另一种看待它的方式:

假设我想在编译时使用宏创建以下类的实例:

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

我从其他地方检索一个函数文字作为变量值:

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

然后我想简单地将该变量夸大到构造中:

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

但它给了我这个错误:

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

通常我可以为自定义类型创建这样的隐式Liftable。但是我还没有找到一种方法来为功能性文字做同样的事情。有没有办法做到这一点,还是我需要以另一种方式看待它?

1 个答案:

答案 0 :(得分:3)

根据我的理解,你试图从一个函数转到一个代表其源代码的抽象语法树(这样它就可以拼接成一个宏扩展)。这是人们要求的常见事情(例如,它经常出现在DSL中),但在我们当前的宏系统中没有直接的方法来实现这一点。

目前您可以做的是在声明函数时明确保存AST,然后在宏中加载并使用它。最方便的方法是通过另一个宏:https://gist.github.com/xeno-by/4542402。人们还可以想象编写一个可以沿着相同的路线工作的宏注释。

在Project Palladium中,有计划为每个正在编译的程序保存类型树。这意味着很可能是一个简单的API,例如treeOf(predicate)将自动返回包含谓词源的抽象语法树。但这绝对不是一成不变的 - 我们会看到它如何发展,我将在今年的ScalaDays上报告进展情况。