每当我不得不在 Scala 中创建 AST 时,我都会使用抽象的密封特征/案例类模式。到目前为止它工作得非常好,让编译器检查模式匹配是一个很大的胜利。
但是现在我遇到了一个我无法解决的问题。如果我有 2 种语言,其中一种是另一种的子集,该怎么办?作为一个简单的例子,考虑一个 lambda 演算,其中每个变量都是绑定的,以及另一种相关的语言,其中变量可以是绑定的或自由的。
第一语言:
abstract sealed class Expression
case class Variable(val scope: Lambda, val name:String) extends Expression
case class Lambda(val v: Variable, val inner: Expression) extends Expression
case class Application(val function: Expression, val input: Expression) extends Expression
第二语言:
abstract sealed class Expression
case class Variable(val name:String) extends Expression
case class Lambda(val v: Variable, val inner: Expression) extends Expression
case class Application(val function: Expression, val input: Expression) extends Expression
唯一的变化是从变量中删除范围。
如您所见,有很多冗余。但是因为我使用的是密封类,所以很难想出一个好的方法来扩展它。组合它们的另一个挑战是,现在每个 Lambda 和应用程序都需要在类型级别跟踪其参数的语言。
这个例子并没有那么糟糕,因为它非常小,但是想象一下对于严格的 HTML/弱 HTML 也有同样的问题。