我有一个架构问题。 我正在使用Dart(尽管语言不太相关)构建计算机代数系统,并希望拥有不可变的表达式树。 BuiltValue 似乎是一个很好的起点,但我在考虑最佳的构建方式。
使用情况:给定一个表达式树和一些操作,高效地构建被操作后的表达式树。例如:
大多数操作将是多个链接操作的结果,我越能避免在每个步骤重建表达式,就越好。有时这是不可能的,例如在复制之后。
天真地说,我可以为每种表达式类型创建一个单独的构建器-IntBuilder、SumBuilder等等,但在这些操作期间,根类型可能会更改。
我考虑过以下事项:
- 每类构建器-虽然我不确定如何更改根类型更改。像Sum([x]).simplify() == x(或上面的第一个示例)这样的简化在重建后不太难处理,但我不确定它们如何与上面的第二个示例一起使用。 - 一个跟踪操作数和某些类似枚举的对象标识结果子类的单个ExpressionBuilder。
我是否忽略了什么非常明显的东西?
使用情况:给定一个表达式树和一些操作,高效地构建被操作后的表达式树。例如:
// 2 + 3 -> 5
Sum([Int(2), Int(3)]).simplify() == Int(5)
// (x + y)^2 -> x^2 + 2*x*y + y^2
Power(Sum([Symbol('x'), Symbol('y')]), Int(2)).expand() == Sum(...)
大多数操作将是多个链接操作的结果,我越能避免在每个步骤重建表达式,就越好。有时这是不可能的,例如在复制之后。
天真地说,我可以为每种表达式类型创建一个单独的构建器-IntBuilder、SumBuilder等等,但在这些操作期间,根类型可能会更改。
我考虑过以下事项:
- 每类构建器-虽然我不确定如何更改根类型更改。像Sum([x]).simplify() == x(或上面的第一个示例)这样的简化在重建后不太难处理,但我不确定它们如何与上面的第二个示例一起使用。 - 一个跟踪操作数和某些类似枚举的对象标识结果子类的单个ExpressionBuilder。
我是否忽略了什么非常明显的东西?
BuiltList
可以具有不同的元素,但它仍将保持为BuiltList
。简化“单个元素的总和是该元素”的方法将具有签名BuiltSum -> BuiltInt
。此外,我假设复合结构的所有子项本身都是BuiltValue
,因此在重建阶段可变。 - DomJack