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:获取 Map.head 元素的键(和值)

    让我们想象一下以下不可变的 Map val foo Map 10 ten 100 one hundred 我想获得第一个元素的密钥 foo head获取第一个元素 但接下来呢 我还想要这个元素的值 即 十 设置键 值对 val key va
  • 使用 slick 3.0.0-RC1 无法在 TableQuery 上找到方法结果

    我正在尝试 Slick3 0 0 RC1我遇到了一个奇怪的问题 这是我的代码 import slick driver SQLiteDriver api import scala concurrent ExecutionContext Imp
  • 在 Scala 中调用反射案例类构造函数

    我可以通过静态反射获取案例类的默认构造函数 val symbol currentMirror classSymbol myObj getClass typeSignature typeSymbol asClass val ctor symb
  • Scala repl 抛出错误

    当我打字时scala在终端上启动 repl 它会抛出此错误 scala gt init error error while loading AnnotatedElement class file usr lib jvm java 8 ora
  • “函数是第一等值”这到底是什么意思?

    有人可以用一些很好的例子清楚地解释它吗 在解释函数式编程时 我在 Scala 中遇到了这句话 一流 并不是一个正式定义的概念 但它通常意味着一个实体具有三个属性 有可能used 不受限制 只要 普通 值可以 即从函数传递和返回 放入容器等
  • 如何设计具有相互依赖的测试的 Specs2 数据库测试?

    有没有一些首选的方法来设计Specs2 http etorreborre github com specs2 测试 有很多测试取决于之前测试的结果 下面 您将找到我当前的测试套件 我不喜欢var位于测试片段之间 不过 它们是 需要的 因为某
  • 通用 scala 函数,其输入是变量数量的函数

    我想定义一个函数f需要另一个函数g 我们需要g采取采取n双打 对于某些固定n 并返回一个 Double 函数调用f g 应该返回具体值n 例如 f Math max 2因为 Math sin 具有类型 Double Double gt Do
  • Akka Stream Graph 恢复问题

    我创建了一个图表来并行化具有相同输入的两个流 这些流产生 Future Option Entity 如果 flowA 失败 我想返回 Future None 但恢复似乎没有被调用 val graph Flow Input Future Op
  • HashPartitioner 是如何工作的?

    我阅读了文档HashPartitioner http spark apache org docs 1 3 1 api java index html org apache spark HashPartitioner html 不幸的是 除了
  • 更改 build.sbt 自定义任务中的版本

    我在 build sbt 中定义了一个自定义任务 val doSmth taskKey Unit smth doSmth version 1 0 SNAPSHOT 但它不会改变版本 我真正想要的是自定义 sbt 发布任务 它将始终将相同的版
  • Spark SQL 失败,因为“常量池已超过 JVM 限制 0xFFFF”

    我在 EMR 4 6 0 Spark 1 6 1 上运行此代码 val sqlContext SQLContext getOrCreate sc val inputRDD sqlContext read json input try inp
  • 从 HList 获取元素

    我尝试了 HList 并按预期进行了以下工作 val hl 1 foo HNil val i Int hl 0 val s String hl 1 但是 我无法让以下代码正常工作 让我们暂时假设对列表进行随机访问是一个聪明的主意 class
  • 高效序列化案例类

    对于我正在工作的图书馆 我需要提供一个高效 便捷 typesafe序列化 scala 类的方法 理想的情况是用户可以创建一个案例类 并且只要所有成员都是可序列化的 它似乎也应该如此 我准确地知道序列化和反序列化阶段的类型 因此不需要 也不能
  • 在 Spark MLlib 上使用 Java 中的 Breeze

    在尝试从Java使用MLlib时 使用微风矩阵运算的正确方法是什么 例如scala 中的乘法很简单 matrix vector 相应的功能在Java中是如何表达的 有一些方法 例如 colon times 可以通过正确的方式调用 breez
  • 如何使用 Spark 2 屏蔽列?

    我有一些表 我需要屏蔽其中的一些列 要屏蔽的列因表而异 我正在读取这些列application conf file 例如 对于员工表如下所示 id name age address 1 abcd 21 India 2 qazx 42 Ger
  • Play框架:单属性案例类的JSON读取

    我正在尝试为包含单个属性的案例类创建隐式 JSON Reads 但收到错误 Reads Nothing 不符合预期类型 这是代码 import play api libs functional syntax import play api
  • 使用 Scala 获取 Spark 数据集中最新时间戳对应的行

    我对 Spark 和 Scala 比较陌生 我有一个具有以下格式的数据框 Col1 Col2 Col3 Col 4 Col 5 Col TS Col 7 1234 AAAA 1111 afsdf ewqre 1970 01 01 00 00
  • 为什么用scala写的代码比用java写的慢6倍?

    我不确定我在编写 scala 代码时是否犯了一些错误 问题是 The four adjacent digits in the 1000 digit number that have the greatest product are 9 9
  • 如何在映射中将字符串转换为 Seq[String]

    我有一个Map String String 以及需要的第三方功能Map String Seq String 有没有一种简单的方法来转换它 以便我可以将地图传递给函数 original mapValues Seq 注意mapValues返回地
  • 在 Scala 中将元素追加到列表末尾

    我无法添加 type 元素T到一个列表中List T 我尝试过myList myElement但它似乎创建了一个奇怪的对象并访问myList last始终返回放入列表中的第一个元素 我怎么解决这个问题 List 1 2 3 4 Result

随机推荐