Scala 宏:类型化(又名类型检查)树和非类型化树之间有什么区别

2024-02-20

我正在开始使用 scala 宏,它们非常棒,但是我遇到了类型化(又名类型检查)和非类型化之间的区别Trees.

例如,您不能调用c.eval由于某种原因使用类型检查的树。我在 scala 宏文档中找不到关于此“类型检查”的文档(我知道他们仍在研究这个问题,这可能有一天需要添加)。

这对一个人来说意味着什么Tree进行类型检查?为什么它们如此不同以至于显然 c.eval 无法处理 typecheckedTree是(相反对我来说更有意义)。

我猜这可能是编译器 101,但我没有参加该课程:( 任何解释或文章/文档的指针将不胜感激!


理论部分

这是 scalac 的一个架构特性,一旦我们在 2.10 中的编译时/运行时反射中公开内部编译器数据结构,它就开始泄漏到公共 API 中。

粗略地说,scalac 的前端由一个解析器和一个打字器组成,两者都与树一起工作并生成树作为结果。然而,这些树的属性有很大不同,这是因为解析器生成的树是无属性的(具有它们的属性)symbol字段设置为NoSymbol和他们的tpe字段设置为null),而 typer 生成的树则被归因。

现在你可能想知道这会带来什么不同,因为它只是symbol and tpe, 正确的?然而,在 scalac 中,它不仅仅如此。为了完成它的工作,typer 改变了它正在处理的 AST 的结构,破坏了一些原始树并生成了一些合成树。不幸的是,有时这些转换是不可逆的,这意味着如果对一棵树进行类型检查,然后删除所有指定的属性,则生成的树将不再有意义(https://issues.scala-lang.org/browse/SI-5464 https://issues.scala-lang.org/browse/SI-5464).

好吧,但是为什么要擦除(或者用 scalac 的说法,重置,如resetLocalAttrs or resetAllAttrs)类型检查树的属性?好吧,这种必要性源于另一个实现细节——符号及其所有者链。就在几天前,我在 scala-internals 上写了一些有关此内容的详细信息:https://groups.google.com/d/msg/scala-internals/rIyJ4yHdPDU/qS-7DreEbCwJ https://groups.google.com/d/msg/scala-internals/rIyJ4yHdPDU/qS-7DreEbCwJ,但简而言之,您不能在某些词汇上下文中对树进行类型检查,然后简单地在不同的词汇上下文中使用它(这是本质上需要的)c.eval).

因此,总结一下 scalac 树管理的最新技术:

  1. 无类型树(也称为解析器树或无属性树)在观察上与类型树(也称为类型树、类型检查树或属性树)不同
  2. 这两种树风格之间有两个主要区别:a)类型化树具有由类型检查器设置的符号和类型,b)类型化树具有稍微不同的形状。
  3. 通常,如果某些编译器 API 采用树,那么无类型树和类型树都可以。然而,在某些情况下(我在上面概述的其中之一),只有无类型或只有类型的树才是合适的。
  4. 可以通过调用从无类型树到类型树Context.typecheck(编译时反射)或ToolBox.typecheck(运行时反射),但是通过以下方式从类型化树返回到非类型化树resetLocalAttrs or resetAllAttrs目前不可靠,因为https://issues.scala-lang.org/browse/SI-5464 https://issues.scala-lang.org/browse/SI-5464.

因此,正如您所看到的,我们的树非常反复无常,这给 Scala 中的元编程带来了很大的复杂性。

然而,好消息是,这种复杂性并不是由源自编译器 101 的一些基本的好理由决定的。所有的复杂性都是偶然的,我们计划逐步驱逐它,直到它全部消失。https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ(几天前也发布过)是朝这个方向迈出的第一步。请继续关注今年也可能推出的其他好东西!

实用部分

在通过详细阐述所有细节并暗示毫无作用的神秘案例彻底吓到您之后,我想指出的是,在使用宏时通常不需要了解此类内容。通常,无类型树(手动构造的 AST、准引号)和类型树(宏参数)都可以正常工作。

在某些情况下,当 scalac 想要特定的树味时,它会告诉你喜欢c.eval或者有时会在你面前崩溃(RefChecks、LambdaLift 和 GenICode 崩溃是树在宏扩展期间混合在一起的巨大指标 - 在这些情况下使用resetLocalAttrs如中所述https://groups.google.com/forum/#!msg/scala-internals/rIyJ4yHdPDU/qS-7DreEbCwJ https://groups.google.com/forum/#!msg/scala-internals/rIyJ4yHdPDU/qS-7DreEbCwJ)。解决这个问题是我的首要任务,我现在正在努力解决这个问题。修复可能会进入 2.11.0,这个答案很快就会过时:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 宏:类型化(又名类型检查)树和非类型化树之间有什么区别 的相关文章

  • Scala:具有复杂结构的树插入尾递归

    我正在 scala 中创建自定义对象树 并且我的插入方法引发堆栈溢出 因为它不是尾递归 但是 我不太清楚如何使其尾递归 我见过使用 累加器 变量的相关示例 但它们要么是只能相乘和覆盖的整数之类的东西 要么是我在适应树时遇到困难的列表 这是我
  • 宏:knownDirectSubclasses 被嵌套类型破坏?

    我有一个宏 它枚举密封特征的直接子类型 import scala reflect macros Context import language experimental macros object Checker def apply A U
  • Scala Array.apply 有何魔力

    来自 scala 2 10 4 的 array scala Array定义为 final class Array T length Int extends java io Serializable with java lang Clonea
  • 如何抑制spark输出控制台中的“Stage 2===>”?

    我有数据帧并试图获取不同的计数并且能够成功获取不同的计数 但是每当 scala 程序执行时我都会收到此消息 Stage 2 gt 1 1 2 我如何在控制台中抑制特定的此消息 val countID dataDF select substr
  • 阶乘的 Scala 排列

    我怎样才能找到n Scala 中某些字母的排列 Scala 2 9 RC1 scala gt abc permutations toList res58 List String List abc acb bac bca cab cba
  • 使用 Spray-json 解析简单数组

    我正在尝试 但失败了 了解 Spray json 如何将 json feed 转换为对象 如果我有一个简单的 key gt value json feed 那么它似乎可以正常工作 但是我想要读取的数据出现在如下列表中 name John a
  • 错误:协变类型 A 出现在逆变位置

    我试图写一个不可变的Matrix A 班级 我希望该类是协变的A但是当我把 在 前面A编译器开始抱怨类中的某些操作 以下是我的相关子集Matrix类 实际类比以下子集大 5 倍左右 class Matrix A private val co
  • Scala 和变量中的模式匹配

    我是 Scala 新手 有点想知道模式匹配是如何工作的 想象一下我有以下内容 case class Cls i Int case b Cls i gt Ok case e Cls gt Ok case f Cls gt Ok case s
  • 缓存 Slick DBIO 操作

    我正在尝试加快 SELECT FROM WHERE name 的速度Play 中的查询类型 Scala 应用程序 我正在使用 Play 2 4 Scala 2 11 play slick 1 1 1 包 该软件包使用Slick 3 1版本
  • 使用 scala 集合 - CanBuildFrom 麻烦

    我正在尝试编写一个接受任何类型集合的方法CC 并将其映射到一个新的集合 相同的集合类型但不同的元素类型 我正在挣扎 基本上我正在尝试实施map but 不在集合本身上 问题 我正在尝试实现一个带有签名的方法 它看起来有点像 def map
  • 使用 scala 在 Flink 中进行实时流预测

    弗林克版本 1 2 0斯卡拉版本 2 11 8 我想使用 DataStream 来使用 scala 中的 flink 模型进行预测 我在使用 scala 的 flink 中有一个 DataStream String 其中包含来自 kafka
  • 如果找不到元素,为什么 Scala 的索引方法返回 -1 而不是 None?

    我一直想知道为什么在 Scala 中使用各种索引方法来确定集合中元素的位置 例如List indexOf List indexWhere 返回 1指示集合中不存在给定元素 而不是更惯用的Option Int 回国有什么特别的好处吗 1代替N
  • scala play框架如何对异步控制器进行单元测试

    使用 Scala play 2 5 版并尝试遵循以下文档中的单元测试控制器指南 https www playframework com documentation 2 5 x ScalaTestingWithScalaTest https
  • 如何访问 Scala XML 中的父元素

    The scala xml包表示带有标记树节点的 XML 但是这棵树在 Scala 2 7 中是单向的吗 因为似乎没有办法访问Elem给定的父级Elem 这似乎同样适用于父母Document 例如 在 XOM 中你有getParent an
  • 到底什么是单例类型?

    什么是单例类型 有什么应用和影响 我们非常欢迎示例 更欢迎外行术语 如果将类型视为一组值 则值的单例类型x是仅包含该值的类型 x 用法示例 模式匹配 case Foo type检查匹配的对象是否与Foo using eq where cas
  • Shapeless 和 gremlin scala:如何返回调用 `as` 的结果?

    所以 我调用这个函数as from gremlin scala case class GremlinScala End Labels lt HList traversal GraphTraversal End def as name Str
  • sbt 项目构建中的多个目标目录

    我有一个这样结构的 sbt 项目 build sbt project build properties plugins sbt src main java smcho App java test java smcho AppTest jav
  • 如何将函数应用于元组?

    这应该是一件容易的事 如何将函数应用于 Scala 中的元组 即 scala gt def f i Int j Int i j f Int Int Int scala gt val p 3 4 p Int Int 3 4 scala gt
  • 在案例类中重载 unapply 方法:scala

    考虑下面的代码 case class User id Int name String object User def unapply str String Some User 0 str Scala 抱怨 错误 无法解析重载未应用 案例类
  • 从 scala 的 Type 获取 ParameterizedType?

    有用的是 scala 的 Universe typeOf 保留了类的类型参数 import scala reflect runtime universe case class X T TypeTag val t typeOf T e g S

随机推荐