Parsing 重写表达式以优化表达式的理论

Parsing 重写表达式以优化表达式的理论,parsing,programming-languages,expression-trees,Parsing,Programming Languages,Expression Trees,假设我有一种语言,我可以输入表达式,就像这个过于简单的例子: if A() > B() then A() else B() end 因此A()和B()是函数,表达式返回两者中较大的一个。评估这一点的简单方法是同时调用A和B,然后再调用其中最大的一个。所以如果A返回10,B返回20,B更大,会被调用两次 我想实现的是一种机制,它将在下面实现,因为a()和B()是确定性的(总是给出相同的结果),所以表达式可以重写为: tmpA = A() tmpB = B() if tmpA > tm

假设我有一种语言,我可以输入表达式,就像这个过于简单的例子:

if A() > B() then A() else B() end
因此A()和B()是函数,表达式返回两者中较大的一个。评估这一点的简单方法是同时调用A和B,然后再调用其中最大的一个。所以如果A返回10,B返回20,B更大,会被调用两次

我想实现的是一种机制,它将在下面实现,因为a()和B()是确定性的(总是给出相同的结果),所以表达式可以重写为:

tmpA = A()
tmpB = B()
if tmpA > tmpB then tmpA else tmpB end
这段代码只调用A和B一次,如果两者的开销相同,那么这将节省33%的执行时间

我想这样做,这样用户就不必担心性能,我的语言是针对业务用户而不是程序员的。用户将像在白板上一样输入表达式,程序将其解析为表达式树,优化器将自动重写该表达式,以便高效执行,然后进行编译

有谁知道有一本好的书或资源可以处理这个话题吗?关于这一点有什么正式的理论吗?上述情况很容易发现,但当事情变得更复杂时,我会感到紧张。当我重写一个表达式并改变行为时,这不是一件好事

一个更复杂的例子是

A = 10
B = if A > 5 then 100 else 0 end
C = if A > 5 then B * 2 else 0 end
我不会让你厌烦所有的细节,但是假设A是一个标志,指示是否应该做某事。中间函数B也是用户可以调用的结果

如果我调用C,它将检查A>5,然后调用B,它将再次检查A,然后返回。所以当我替换(内联)表达式时,我会得到

C = if A > 5 then if A > 5 then 100 else 0 end * 2 else 0 end
这可以优化为

C = if A > 5 then 200 else 0
在一个典型的模型中,有数百个这样的表达式,它们相互调用递归函数,所以这些事情可能会变得非常复杂。如果可能的话,我不想通过试验和性爱来发现这一点,而是想了解其他人在这一领域所做的事情

提前感谢,


Gert Jan

只是一个想法,但是如果你让你的代码引用一个预先填充的变量来替换所有重复的方法调用(在第一次调用之前填充,以避免不必要的调用),你就不能让编译器处理剩下的

我可能错了,但我认为他们已经在这些类型的优化上投入了相当多的精力。。取决于语言、编译器(有时还有编译选项),但这些都比整个代码优化更快


不过这只是一个建议,只是一个想法,但是如果你让你的代码引用一个预先填充的变量来替换所有重复的方法调用(在第一次调用之前填充,以避免不必要的调用),你就不能让编译器来处理剩下的

我可能错了,但我认为他们已经在这些类型的优化上投入了相当多的精力。。取决于语言、编译器(有时还有编译选项),但这些都比整个代码优化更快


不过,这只是一个建议

您是否试图确定函数何时具有确定性?如果是这样,那就属于停顿问题,这是NP难的。@cdhowie停顿问题不是NP难的,它实际上是不可判定的。@Howard:嗯,你说得对。不久前我在一起研究这些概念,我想它们在我的脑海中已经变得有些模糊了。无论如何,如果语言是图灵完备的,编译器就不能指望以100%的准确度找出哪些函数是确定性的。嗨,不,语言很像excel,所以引用另一个“单元”就是确定性的,我提供的任何函数都会有元数据来指示它们是否具有确定性。您是否试图确定函数何时具有确定性?如果是这样,那就属于停顿问题,这是NP难的。@cdhowie停顿问题不是NP难的,它实际上是不可判定的。@Howard:嗯,你说得对。不久前我在一起研究这些概念,我想它们在我的脑海中已经变得有些模糊了。无论如何,如果语言是图灵完整的,编译器就不能指望以100%的准确度找出哪些函数是确定性的。嗨,不,语言很像excel,所以对另一个“单元格”的引用是确定性的,我提供的任何函数都会有元数据来指示它们是否是确定性的。嗨,谢谢,这与我所做的差不多,但也有其他情况,例如一个类的集合,如db,在sql中要说sum(a)*sum(b),然后重写为sum(a*b),我只会在集合上迭代一次。这个想法是用户可以很天真地指定应该做什么,代码仍然很快。这个例子应该是sum(a)+sum(b)->sum(a+b),上面的例子将返回另一个结果..是的,这很难。。实现缓存是我能做的最远的事情;-)(如果你必须获得更好的优化,我会参考编译器书籍,因为在某种程度上,你似乎想要创建自己的语言,并且可能需要一个运行时来获得重大改进)。我能想到的唯一一件事是(试着想象你为什么会需要这个)分析代码,为所有要运行的命令创建某种类型的数据立方体..您好,谢谢,这与我所做的差不多,但还有其他情况,例如,像db这样的类集合,在sql中要说sum(a)*sum(b),然后重写将是sum(a*b),我只会在集合上迭代一次。这个想法是用户可以很天真地指定应该做什么,代码仍然很快。这个例子应该是sum(a)+sum(b)->sum(a+b),上面的例子会返回另一个结果。是的,这很难