Scala 更新不可变AST的最简单方法是什么?

Scala 更新不可变AST的最简单方法是什么?,scala,macros,abstract-syntax-tree,scala-2.10,Scala,Macros,Abstract Syntax Tree,Scala 2.10,在使用宏时,我已经到了需要更新AST中那些具有特定条件的节点的地步(我一直在努力避免)。例如,假设我想更新每个节点: Literal(Constant(1)) 具有以下值: Literal(Constant(2)) 这些AST节点可能位于表达式树中的任何位置,因此我不能使用特殊模式匹配器。显然,我最不想做的就是编写一个完整的模式匹配器,它能够覆盖所有的编译器原语。我一直在中搜索,但我的印象是,collect和traversable family等方法不足以满足我的需求,因为它们将树视为线性对

在使用宏时,我已经到了需要更新AST中那些具有特定条件的节点的地步(我一直在努力避免)。例如,假设我想更新每个节点:

Literal(Constant(1))
具有以下值:

Literal(Constant(2))

这些AST节点可能位于表达式树中的任何位置,因此我不能使用特殊模式匹配器。显然,我最不想做的就是编写一个完整的模式匹配器,它能够覆盖所有的编译器原语。我一直在中搜索,但我的印象是,collect和traversable family等方法不足以满足我的需求,因为它们将树视为线性对象,因此我希望得到整个更新的树。那么,有可能以智能的方式更新不可变的表达式树吗?为什么在标准API中不存在这样的“更新”操作?

一般地修改数据结构中的多类型节点是数据类型泛型(通过类型构造函数参数化代码)的一个典型案例

有几种方法可用于此类操作,例如定义数据类型通用遍历函数的方法

在Haskell中,节点更新函数在两个维度上被参数化:按数据类型和按代码——因此您可以在结构中的任何位置将不同的更新函数应用于不同的类型:

-- | Apply a transformation everywhere in bottom-up manner
everywhere :: (forall a. Data a => a -> a)
           -> (forall a. Data a => a -> a)

在Haskell中这样做在很大程度上依赖于类型类。在Scala中,有几个

以下是在Scala宏中使用AST转换器的示例:


对于插件,有一个树形转换器。我想宏肯定有类似的功能,甚至可能是相同的。如果他不是在宏的上下文中询问的话,我想你可能会想看看@NikitaVolkov。我所说的-但它似乎只是针对插件。变形金刚看起来真的很有趣。我将寻找它在宏中的可能应用。非常感谢。我真的必须查找Transformer的源代码。它看起来像XML转换库,并且该库在树的深度上具有指数级的性能。这是一个简单的问题:这与自顶向下和自底向上的遍历有关吗?在自上而下的遍历中,更改叶子意味着重建上面的树。上面链接中的
traceImpl
的实现表明新树是自下而上构造的(至少在那里)。但是,一般来说,这取决于如何调用
super.transform