gpt4 book ai didi

scala - 如何确定传递给宏的表达式是否始终产生相同的值?

转载 作者:行者123 更新时间:2023-12-02 03:23:29 25 4
gpt4 key购买 nike

假设我定义了一个宏,如下所示。它本质上是键入类型 T 的表达式并返回类型为 MyType[T] 的对象(涉及的实际类型并不重要)。

object MyMacro {
def macroImpl[T : context.WeakTypeTag, U : context.WeakTypeTag](context : scala.reflect.macros.blackbox.Context) (expression : context.Expr[T]) : context.Expr[U] =
}

object MyObj {
def callMacro[T](expression : T) : MyType[T] = macro MyMacro.macroImpl[T, MyType[T]]
}

在我的宏中,我想确定传递的表达式是否为常量。我的意思是,我想知道表达式一旦在运行时求值,是否可以随后求值为不同的值。如果它是常数,我可以应用某些非常有用的优化。

我知道一个表达式是常数,如果它是:

  • 文字表达式。
  • “这个”表达式。
  • 对 val 或参数的引用。
  • 一个成员调用,其中对象表达式是常量,被调用的成员是一个 val 或 lazy val。

例如,在下面对 callMacro 的前五次调用中传递的表达式应被视为常量:

class MyClass {
val i = 0

val myLiteral = callMacro("Hi!") //constant - literal expression

val myThis = callMacro(this) //constant - this expression

val myInt = callMacro(i) //constant - reference to a val

def myMethod(p : MyOtherClass) {
val myParameter = callMacro(p) //constant - reference to a parameter
val myValMember = callMacro(p.x) //constant - invocation of val member
val myVarMember = vallMacro(p.y) //NOT constant - invocation of var member
val myVarMember = vallMacro(p.z) //NOT constant - invocation of def member
}
}

class MyOtherClass(val x : Int, var y : Int) {
def z = x + y
}

我已经为前两个案例实现了代码(这很简单)。

def isConstant[T](context : scala.reflect.macros.blackbox.Context) (expression : context.Expr[T]) = {
import context.universe._
expression.tree match {
case This(_) =>
true
case Literal(_) =>
true
/*...put additional cases here...*/
case _ =>
false
}
}

但是,我不确定这样的东西是否已经存在,或者是否有可能检测到在对象上调用的成员是否是 val。

是否可以执行第四个标准?或者,API 中是否已经存在类似的内容?

最佳答案

我想出了一个解决办法。基本上归结为我不了解比例尺反射系统中的符号。

我最后添加了第五个标准来处理引用隐式参数或对象的情况。

implicit class extendSymbol(symbol : scala.reflect.macros.blackbox.Context#Symbol) {
def isStable =
(symbol.isTerm && symbol.asTerm.isStable) || (symbol.isMethod && symbol.asMethod.isStable)
}

def isConstant[T](context : scala.reflect.macros.blackbox.Context) (tree : context.Tree) : Boolean = {
import context.universe._
tree match {
case This(_) =>
true
case Literal(_) =>
true
case ident @ Ident(_) =>
ident.symbol.isStable
case select @ Select(objExpr, term) =>
isConstant(context) (objExpr) && select.symbol.isStable
//for implicit values
case Apply(TypeApply(Select(Select(This(TypeName("scala")), TermName("Predef")), TermName("implicitly")), _), _) =>
true
case _ =>
false
}
}

关于scala - 如何确定传递给宏的表达式是否始终产生相同的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31654139/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com