首先,背景:
作为一个辅助项目,我正在用Python构建一个计算机代数系统,它可以产生解决方程所需的步骤。
到目前为止,我已经能够将代数表达式和方程式解析为表达式树。它的结构是这样的(不是实际的代码 - 可能没有运行):
# Other operators and math functions are based off this.
# Numbers and symbols also have their own classes with 'parent' attributes.
class Operator(object):
def __init__(self, *args):
self.children = args
for child in self.children:
child.parent = self
# the parser does something like this:
expr = Add(1, Mult(3, 4), 5)
除此之外,我还有一系列递归操作以简化表达式的函数。它们不是纯粹的功能,但我试图避免依赖于操作的可变性,而是返回我正在使用的节点的修改副本。每个函数看起来像这样:
def simplify(node):
for index, child in enumerate(node.children):
if isinstance(child, Operator):
node.children[index] = simplify(node)
else:
# perform some operations to simplify numbers and symbols
pass
return node
挑战来自于“一步一步”的部分。我希望我的“简化”函数都是嵌套的生成器,它们“产生”解决问题所需的步骤。所以基本上,每次每个函数执行一个操作时,我都希望能够做到这样的事情:yield (deepcopy(node), expression, "Combined like terms.")
这样依赖于这个库的任何东西都可以输出如下内容:
5x + 3*4x + 3
5x + 12x + 3 Simplified product 3*4x into 12x
17x + 3 Combined like terms 5x + 12x = 17x
但是,每个函数只了解它正在运行的node
,但不知道整体expression
是什么样的。
所以这是我的问题:保持整个表达式树的“状态”以保证每个“步骤”都知道整个表达式的最佳方法是什么?
以下是我提出的解决方案:
5x + 4x = 9x
,请让顶级函数找到(5x + 4x)节点并将其替换为'9x'。这似乎是最好的解决方案,但是如何最好地“重建”每一步?最后两个相关问题:这有什么意义吗?我现在的系统里有很多咖啡因,不知道我是不是很清楚。
我是否担心可变性?这是一个过早优化的案例吗?
答案 0 :(得分:1)
你可能会问树拉链。检查:Functional Pearl: Weaving a Web并查看它是否适用于您想要的内容。从阅读你的问题,我认为你要求在树结构上进行递归,但能够根据需要导航回到顶部。拉链充当“面包屑”,让你回到树的祖先。
我在JavaScript中实现了一个。
答案 1 :(得分:0)
您使用Polish notation构建树吗?
对于逐步简化,您只需使用循环,直到不能在树中进行修改(操作)。