函数式编程是否展示控制流?

Does functional programming exhibit control flow?

函数式编程必须处理与其他所有范例相同的编程方面。没有什么会消失,而是通过不同的抽象隐藏起来。我经常读到控制流专门连接到语句,因此 FP 显示 none。我认为这种说法具有误导性。

有一个完整的类型 class 来模拟命令式控制流 (Monad)。运算符具有优先级和结合性,其他特殊类型遵守进一步的算术法则(按照惯例)。有 if/then/elsecase 语句。懒惰必须考虑。

关联性可能对控制流的影响最大,因为它很常见并且允许并行计算。所以即使控制流不再那么明显了,还是有的,对吧?

但也许我只是将评估和执行顺序混为一谈。希望这个问题不要太宽泛。

理论上,纯函数式编程允许使用多种策略对表达式求值。不同的语言实现可以决定使用不同的策略来减少表达式。例如,在 e1 + e2 中,我们可能首先评估 e1,首先评估 e2,或者甚至同时评估两者。

要评估if guard then e1 else e2我们可以先评估guard,然后只评估相应的分支。原则上,我们甚至可以开始并行评估所有 guarde1e2,并杀死与未采用分支对应的线程。或者我们甚至可以使用更奇怪的方法,我们尝试使用静态分析来证明 guard 终止:如果成功,则 e1e2 的并行计算在 guard 到两个 等于 值,我们只是 return 并杀死仍在评估 guard 的线程,因为我们发现我们毕竟不需要那个。

有几篇论文介绍了如何使用图约简技术在 lambda 演算中执行“最佳约简”。

由于这些不同的策略最终会达到相同的结果,因此除了性能原因外,在它们之间进行选择是无关紧要的。

在实践中,GHC 减少策略并不是那么激进。它不会自动并行化任何东西。如果我没记错的话,它不遵循“最佳缩减”算法,而是一种更直接的算法,其中包含一系列优化和技巧以利用现代硬件。 GHC 过去采用 push/enter 抽象机,但从那以后,当它变得更快时,就切换到更直接的 eval/apply 了。

GHC 抽象机(STG 机)使用一种策略,使 if then else 等表达式具有固定的求值顺序。如果愿意,您可以将其视为“控制流”:始终首先评估 guard,然后仅评估选定的分支。

了解所采用的策略有助于评估程序的复杂性(即使由于懒惰,这在 GHC Haskell 中仍然是一项艰巨的任务)。为此,从某种意义上说,我们需要知道该策略使用的“控制流”。

但是,在评估程序的正确性时,该策略并不重要。如果我们想证明我们的程序是正确的,我们不需要假设一个特定的评估策略,因为它们都会产生相同的结果。