【问题标题】:Why does Scala reify not work as according to the docs?为什么Scala reify 不能按照文档工作?
【发布时间】:2014-02-15 21:59:04
【问题描述】:

2.10.3 的 Scala API 文档说我可以“使用 refiy 生成表示给定 Scala 表达式的抽象语法树”。因此,我可以这样做:

scala> val uni = scala.reflect.runtime.universe 
uni: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@4e42766

scala> uni reify { 1 to 3 } 
res2: uni.Expr[scala.collection.immutable.Range.Inclusive] = Expr[scala.collection.immutable.Range.Inclusive](Predef.intWrapper(1).to(3))

在上面的示例中,我得到了我正在寻找的内容:Predef.intWrapper(1).to(3))(要执行的操作的方便扩展表示)。

但是,当我尝试具体化 1 + 3 时,我并没有表示我想要执行的操作。

scala> uni reify { 1 + 3 }
res5: uni.Expr[Int(4)] = Expr[Int(4)](4)

这是预期的行为吗? + 是原始操作,因此没有具体化吗?

Scala 文档显示了一个具体化示例,这意味着可以使用更有用的表示:

reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("$plus")), List( Literal(Constant(4)) ) )

如何检查 1 + 3 的正确扩展表示(如果存在)以及如何检索任何表达式的详细表示(就在上面)?

编辑:我现在看到 Scala 文档中的表示形式是由 showRaw 生成的。但是,我仍然无法重现上面示例中 2 + 4 的原始表示形式。

【问题讨论】:

    标签: scala abstract-syntax-tree reification


    【解决方案1】:

    参见 Eugene Burmako 的 this answer

    宏被连接到类型检查中(在宏参数的意义上 在宏扩展之前进行类型检查)和类型检查折叠 常量

    reify 使用宏实现。

    你应该防止像这样的不断折叠:

    {
      val i = 1
      showRaw{ reify{i + 2}.tree }
    }
    // Apply(Select(Ident(newTermName("i")), newTermName("$plus")), List(Literal(Constant(2))))
    

    【讨论】:

    • 为了使用您的解决方法,我必须更改我正在具体化的代码。这并不总是那么容易。没有别的办法吗?
    • 另外,2.10.3 的 Scala 文档在显示 reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("$plus")), List( Literal(Constant(4)) ) ) 时是否错误?
    • @AndrewMcKinlay:请注意,在编译时2 + 4 将折叠为6,因此在运行时将只有一个常量6。我不知道防止不断折叠的其他方法。如果您正在开发某种 DSL,您可以使用字符串插值,例如 math"1 + 2"
    • @AndrewMcKinlay:不,没有参数类型检查的宏是White Box macros(参见Evolution of Scala Macros),它们只会在2.12 中引入。我不知道文档中这个错误的历史。
    • 修复了文档:github.com/scala/scala/pull/3414。这是文档中的一个明显的疏忽——宏从来没有这样表现过。感谢您接住它,很抱歉造成混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    • 1970-01-01
    • 1970-01-01
    • 2021-05-29
    相关资源
    最近更新 更多