对于我正在做的一个副项目,我目前必须处理一个抽象语法树并根据规则对其进行转换(细节并不重要)。
AST 本身是不平凡的,这意味着它具有仅限于某些类型的子表达式。(例如,运算符A
必须采用B
仅类型的参数,而不是 any Expr
。我的数据类型的一个大大简化的简化版本如下所示:
data Expr = List [Expr]
| Strange Str
| Literal Lit
data Str = A Expr
| B Expr
| C Lit
| D String
| E [Expr]
data Lit = Int Int
| String String
我的目标是排除显式递归并改为依赖递归方案,正如这 两篇优秀的博客文章所展示的那样,它们提供了非常强大的通用工具来操作我的 AST。应用必要的因式分解,我们最终得到:
data ExprF a = List [a]
| Strange (StrF a)
| Literal (LitF a)
data StrF a = A a
| B a
| C (LitF a)
| D String
| E [a]
data LitF a = Int Int
| String String
如果我没有搞砸,type Expr = Fix ExprF
现在应该与之前定义的Expr
.
然而,为这些案例编写cata
变得相当乏味,因为我必须在 for 内部进行模式匹配才能B a :: StrF a
进行良好的类型化。对于整个原始 AST,这是不可行的。Str :: ExprF a
cata
我偶然发现了修复 GADTs,在我看来这似乎是解决我的问题的方法,但是重复的高阶类型类等用户不友好的界面是相当不必要的样板。
所以,总结一下我的问题:
- 将 AST 重写为 GADT 是解决此问题的正确方法吗?
- 如果是,我如何将示例转换为运行良好的版本?第二点,现在 GHC 中是否有对更高种类的更好的支持
Functor
?