Bar*_*zak 5 scala scala-macros
我一直想为Scala实现一个链式比较运算符,但经过几次尝试后,我认为没有办法实现它.这是它应该如何工作:
val a = 3
1 < a < 5 //yields true
3 < a < 5 //yields false
Run Code Online (Sandbox Code Playgroud)
问题是,scala编译器在计算表达式时非常贪婪,因此上面的表达式计算如下:
1 < a //yields true
true < 5 //compilation error
Run Code Online (Sandbox Code Playgroud)
我试图编写代码以某种方式实现它,这是我尝试过的:
Int到我的类型的隐式转换RichComparisonInt- 由于上面的评估方式没有帮助,Int我的同班同学-不能完成,因为Int既abstract和final,case class用名字创建<,就像::,但后来我发现,这个类只是为了模式匹配而创建的,=> Boolean,它可以在编译级别上工作,但是没有办法提取操作的参数,从而导致Boolean结果.有没有办法在Scala中做到这一点?也许宏可以完成这项工作?
这是一个使用macros. 这里的一般方法是丰富Boolean,以便它有一个macro方法可以查看prefix上下文的 来查找用于生成该 的比较Boolean。
例如,假设我们有:
implicit class RichBooleanComparison(val x: Boolean) extends AnyVal {
def <(rightConstant: Int): Boolean = macro Compare.ltImpl
}
Run Code Online (Sandbox Code Playgroud)
以及macro带有方法头的定义:
def ltImpl(c: Context)(rightConstant: c.Expr[Int]): c.Expr[Boolean]
Run Code Online (Sandbox Code Playgroud)
现在假设编译器正在解析表达式1 < 2 < 3。我们显然可以在评估宏方法体时使用c.prefix来获取表达式。然而,恒定折叠1 < 2的概念阻止我们在这里这样做。常量折叠是编译器在编译时计算预定常量的过程。因此,当宏被求值时,已经被折叠到这种情况下。我们已经失去了导致 的表达方式。您可以在这个问题上阅读有关常量折叠及其与 Scala 宏的交互的更多信息,以及有关此问题的一些内容。c.prefixtrue1 < 2true
如果我们可以将讨论的范围限制为仅形式的表达式C1 < x < C2,其中C1和C2是常量,并且x是变量,那么这是可行的,因为这种类型的表达式不会受到常量折叠的影响。这是一个实现:
object Compare {
def ltImpl(c: Context)(rightConstant: c.Expr[Int]): c.Expr[Boolean] = {
import c.universe._
c.prefix.tree match {
case Apply(_, Apply(Select(lhs@Literal(Constant(_)), _), (x@Select(_, TermName(_))) :: Nil) :: Nil) =>
val leftConstant = c.Expr[Int](lhs)
val variable = c.Expr[Int](x)
reify((leftConstant.splice < variable.splice) && (variable.splice < rightConstant.splice))
case _ => c.abort(c.enclosingPosition, s"Invalid format. Must have format c1<x<c2, where c1 and c2 are constants, and x is variable.")
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们将上下文prefix与预期类型相匹配,提取相关部分 (lhs和x),使用 构造新的子树,并使用和c.Expr[Int]构造新的完整表达式树以进行所需的三向比较。如果与预期类型不匹配,则编译失败。 reifysplice
这使我们能够:
val x = 5
1 < x < 5 //true
6 < x < 7 //false
3 < x < 4 //false
Run Code Online (Sandbox Code Playgroud)
如预期的!
有关宏、树的文档和本演示文稿是了解有关宏的更多信息的良好资源。
| 归档时间: |
|
| 查看次数: |
275 次 |
| 最近记录: |