11.3.1不同的计算策略
Haskell 是一种纯函数式语言。一个有趣方面是,它不允许有任何副作用。有专门的技术来打印到屏幕,或处理文件系统,但对于程序员来说,它以一种看起来不像有副作用的方式来实现。在这样的语言中,计算时重新排序表达式是可能的,因此,Haskell 中,直到需要这个结果,才计算函数。这不会影响程序的结果,因为,函数没有副作用。
C# 和 F# 的函数都可能有副作用。他们在 F# 中是障碍,因此,语言提供多种方式以避免,但他们仍然可以在程序出现。这两种语言指定表达式运行的顺序,否则,我们不能发现哪个副作用会首先出现,提供可靠的编程是不可能的!
C# 和 F# 中的提前计算
在大多数主流的语言中,指定指定顺序的规则很简单:写一个函数调用,程序计算所有的参数,然后执行函数。让我们用前面的例子来演示:
TestAndCalculate(Calculate(10));
在所有的主流语言中,程序将执行 Calculate(10),然后,把这个结果作为参数值传递给 TestAndCalculate。正如我们在前面的示例中已经看到的,这是不幸的,如果函数 TestAndCalculate 不需要这个参数值。在这种情况下,我们只是无故地浪费了一些 CPU 周期!这
称为提前计算策略(eager evaluation strategy)。
提前计算的好处是,它很容易理解程序如何执行的。在 C# 和 F# 中,这是很重要的,因为,我们需要知道哪种顺序它的副作用(比如I / O和用户界面操纵)将运行。在 Haskell 中,这是由参数值和函数的返回值控制的,所以,对于顺序,我们并不需要知道的更多。
在 Haskell 中的延迟计算策略
在一个延迟计算策略中,给函数的参数值在函数被调用时,都不会计算,到后来当这个值需要时才计算。让我们回到前面的例子:
TestAndCalculate(Calculate(10));
在这里,Haskell 直接跳转到 TestAndCalculate。参数值的名字叫 num,Haskell 会记住,如果在后面会需要 num 值,它会运行 Calculate(10) 以得到它。然后,它继续执行,得到 TestCondition 的结果。如果这个函数返回 true,它需要值 num,执行 Calculate(10)。如果 TestCondition 返回 false,Calculate 函数根本不调用。