有没有一种方法可以使函数文字的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。但我还没有找到一种方法来做同样的功能文字。有没有办法做到这一点,或者我需要换一种方式来看待它?
据我所知,您正试图从一个函数转到一个表示其源代码的抽象语法树(以便将其拼接到宏扩展中)。这是人们经常要求的事情(例如,它经常出现在DSL中),但在我们当前的宏观系统中,没有直接的方法来实现这一点。
目前,您可以做的是在声明函数时显式保存AST,然后在宏中加载并使用它。最方便的方法是通过另一个宏:https://gist.github.com/xeno-by/4542402.人们还可以想象写一个宏注释,它将按照相同的思路工作。
在Project Palladium中,有一个为正在编译的每个程序保存类型检查树的计划。这意味着很可能会有一个简单的API,例如treeOf(predicate)
,它将自动返回包含谓词源的抽象语法树。但这绝对不是板上钉钉的事情——我们会看看进展如何,我会在今年的ScalaDays上汇报进展。