我是具有命令式背景的新手 Haskell 程序员。
我正在编写一个程序来解析具有循环的抽象语法树(或者更确切地说是一个图)。(这实际上是 GCC 的通用 AST)。我正在设计用于表示此图的数据类型,但我遇到了困难:
首先,GCC AST 中有很多讨厌的循环。例如,类型声明指的是实际的类型描述符,它指的是类型的声明(这个声明有时可能与原始声明不同,有时它只是对标识符节点的引用)。所有树节点都引用一个所谓的上下文节点(父引用的一种形式)。但是,这个上下文节点(对于某些节点 X)通常与最初引用 X 的节点不同。例如,可以从 C++ 命名空间节点中找到某个内置函数的声明,但函数声明的上下文指向一个翻译单位声明。Perhpas 这使得使用拉链成为不可能?我也不能忽略这些上下文节点,因为它们对于找出声明的范围很有用。
因此,在设计数据结构时,我应该考虑这样一个事实,即有时我不知道在运行时我将处理什么样的节点。但是,当我确定节点将具有已知类型时,我希望能够在类型级别上反映这一点并利用静态类型检查(例如函数的结果类型始终是类型,而不是整数常量, 但它可能是整数或指针类型等)。
其次,GCC 树是面向对象意义上的分层数据类型。所有节点都有共同的信息,例如它们是什么类型的节点。所有声明都有一个名称和许多标志,变量声明还有类型信息。许多节点拥有如此多的数据,以至于仅通过模式匹配来访问这些信息是不方便的。所以我很可能会使用访问器函数(和类型类来提供统一的接口,而不管节点类型如何)。
第三,我希望我的图表纯粹是功能性的,但我不知道如何构建它。我的输入是文本,每个节点都有一个部分。节点由唯一的 id 标识,并且有很多前向和自引用。
因此,以我的背景,我感觉到我正在尝试将我的 Haskell 接口强制为命令式形式。所以我想请你提供一些具体的建议来指导我设计我的数据类型、它们的接口以及如何构建图表。
到目前为止,我已经决定我不会结婚。它会阻止我对树进行转换(恕我直言,应该进行一些转换)。如果有一天我想这样做,也很难将这棵树写回磁盘。
编辑:这是我的输入示例。它在 YAML 中,但格式尚未确定(我正在从 GCC 中自己生成这些数据)。 http://sange.fi/~aura/test.yaml该示例包含全局命名空间,其中一个函数声明为 (int main (int argc, char *argv[]))。
提前致谢!