是的,文学作品是存在的,抱歉我不能引用任何内容,我只是不记得了,你可以用谷歌搜索一下吗..
依赖和循环分析的基本算法非常简单。 IE。检测表达式中的符号,在form中构建一组表达式和依赖:
inps expr outs
cell_A6, cell_B7 -> expr3 -> cell_A7
cell_A1, cell_B4 -> expr1 -> cell_A5
cell_A1, cell_A5 -> expr2 -> cell_A6
然后通过比较和迭代扩展/替换输入/输出集:
step0:
cell_A6, cell_B7 -> expr3 -> cell_A7
cell_A1, cell_B4 -> expr1 -> cell_A5 <--1 note that cell_A5 ~ (A1,B4)
cell_A1, cell_A5 -> expr2 -> cell_A6 <--1 apply that knowledge here
so dependency
cell_A1, cell_A5 -> expr2 -> cell_A6
morphs into
cell_A1, cell_B4 -> expr2 -> cell_A6 <--2 note that cell_A6 ~ (A1,B4) and so on
最后,您将获得一组完整的依赖关系,您可以在其中轻松检测循环依赖关系,例如:
cell_A1, cell_D6, cell_F7 -> exprN -> cell_D6
或者,如果没有找到 - 您将能够确定一个安全的增量执行顺序。
如果表达式包含除“返回值”之外的分支或副作用,您可以应用各种转换将表达式缩减/扩展为新的表达式,或将具有上述形式的新表达式组。例如:
B5 = { if(A5 + A3 > 0) A3-1 else A5+1 }
so
inps ... outs
A3, A5 -> theExpr -> B5
the condition can be 'lifted' and form two conditional rules:
A5 + A3 > 0 : A3 -> reducedexpr "A3-1" -> B5
A5 + A3 <= 0 : A5 -> reducedexpr "A5-1" -> B5
但是现在,您的执行/分析还必须在应用规则之前注意条件。提升只是可能的转变之一。
但是,您仍然需要更多的东西,至少需要一些“扩展”。你的问题的难点在于你的表达式很复杂,有分支,你需要包含用户随机输入来解析分支,以消除死分支并打破死依赖。
由于关键是消除死依赖,您必须以某种方式检测死分支。条件可以是任意复杂的,用户输入是随机的,所以你不能完全静态地解决它,真的。在使用转换之后,您仍然需要分析条件并相应地生成代码。为此,您需要为条件结果的所有可能组合以及所有产生的分支和规则组合生成代码,除了一些琐碎的情况外,这根本不可行。随着未知的数量,叶子的数量可以呈指数增长(2 ^ N),这在超过某个阈值后是一个巨大的膨胀。
当然,在基于布尔值分析条件时,您可以分析、分组和消除冲突条件,例如(a & b & !a)..
..但是如果您的输入值和条件包括非布尔数据,如整数或浮点数或字符串,请想象您的条件是有一个执行某些外部奇怪统计函数并检查其结果的条件..忽略“奇怪” '部分并专注于'外部'。如果您遇到一些使用复杂函数(如 AVG 或 MAX)的表达式,则无法静态地咀嚼类似的东西(*)。即使是简单的算术也很难分析:(a+b)*(c+d) - 你可以推导出一个事实,当 a+b==0 时c+d 可以忽略,但要完全覆盖这是一项非常艰巨的任务..
IIRC,使用基本运算符对布尔表达式进行可满足性分析 (SAT) 是一个 NP 难题,更不用说整数或浮点及其所有数学运算了。计算表达式的结果比告诉哪些值更容易这真的取决于!
因此,由于输入值可能是硬编码(很酷)或在运行时由用户提供(doh!),因此您的编译器很可能无法预先对其进行全面分析。现在将它与标记为 (*) 的事实联系起来,很明显您可以包含一些静态分析并尝试在“编译时”消除一些分支,但仍然可能有一些部分必须延迟到用户提供实际输入。
所以,如果部分分析必须在运行时完成,所有的分支消除只是一个可选的优化,我认为你现在应该专注于运行时部分。
在最小的未优化版本中,您生成的程序可以简单地记住所有 excel 表达式并等待输入数据。一旦程序运行并给出输入,程序就必须在表达式中替换输入,然后尝试迭代地将它们简化为输出值。
用命令式语言编写这样的算法是完全可能的。实际上,您需要编写一次,然后将其与从单元公式派生的不同规则集合并并完成。程序的运行时部分是相同的,公式会改变。
然后您可以扩展“编译器”端以尝试提供帮助,即初步部分分析依赖关系并尝试重新排序规则,以便稍后以“更好的顺序”检查它们,或通过预先计算常量或内联一些表达式等等,但正如我所说,这都是优化,而不是核心功能。
遗憾的是,我无法真正告诉您有关“函数式语言”的任何严肃内容,但由于它们的运行时通常是“非常动态的”,有时它们甚至会根据符号和转换来执行代码,它可以降低您的“编译器”和“引擎”部分。这里最宝贵的资产是活力。因此,即使是 Ruby 也会比 C 做得更好——但它绝不是你所说的“编译”语言。
例如,您可以尝试将 excel 规则直接转换为函数:
def cell_A5 = expr1(cell_A1, cell_B4)
def cell_A7 = expr3(cell_A6, cell_B7)
def cell_A6 = expr2(cell_A1, cell_A5)
把它写成程序的一部分,然后在运行时当用户提供一些值时,你会重新定义程序的一些部分
cell_B7 = 11.2 // filling up undefined variable
cell_A1 = 23 // filling up undefined variable
cell_A5 = 13 // overwriting the function with a value
这就是动态平台的力量,这里没有什么非常“实用”的东西。动态平台使填充/覆盖位变得容易。但是,一旦用户提供了一些位并且程序已经“即时修正”,你会先调用哪个函数?
答案有些悲哀。。你不知道。
如果您的动态语言内置了一些规则引擎,您可以尝试生成规则而不是函数,然后依靠该引擎“填充”所有可能计算的内容。
但如果它没有规则引擎,你就回到第一点..
三思而后行:
嗯..对不起,我想我写的太多了,太含糊/闲聊了。如果您认为它有帮助,请给我评论。否则我会在几天或一周后删除它。