Haskell/严格性
严格评估,或称为急切评估,是一种评估策略,其中表达式在绑定到变量后立即进行评估。例如,在严格评估中,当读取 x = 3 * 7
时,3 * 7 会立即计算,并将 21 绑定到 x。相反,在惰性评估 中,值只有在需要时才会计算。在 x = 3 * 7
的示例中,3 * 7 只有在需要时才会评估,比如你想要输出 x 的值。
惰性评估通常涉及称为 thunk 的对象。thunk 是一个占位符对象,它指定了不是数据本身,而是如何计算该数据。一个实体可以用 thunk 代替,以计算该实体。当一个实体被复制时,它是否是一个 thunk 并不重要 - 它会被按原样复制(在大多数实现中,会创建一个指向数据的指针)。当一个实体被评估时,首先会检查它是否是一个 thunk;如果是 thunk,则执行它,否则返回实际数据。正是 thunk 的魔力使得惰性评估能够实现。
一般来说,在实现中,thunk 实际上只是一个指向代码片段(通常是静态代码)的指针,加上另一个指向代码应该处理的数据的指针。如果 thunk 计算的实体大于指向代码和相关数据的指针,那么 thunk 在内存使用方面就占优势。但是,如果 thunk 计算的实体更小,那么 thunk 最终会使用更多内存。
例如,考虑使用表达式 iterate (+ 1) 0
生成的无限长度列表。列表的大小是无限的,但代码只是一个加法指令,两个数据 1 和 0 只是两个整数。在这种情况下,表示该列表的 thunk 比实际列表占用更少的内存,而实际列表会占用无限的内存。
然而,再举个例子,考虑使用表达式 4 * 13 + 2
生成的数字。该数字的值是 54,但在 thunk 形式下,它是一个乘法、一个加法和三个数字。在这种情况下,thunk 在内存方面处于劣势。
通常,上面第二种情况会消耗如此多的内存,以至于会消耗整个堆并强制垃圾收集器运行。这会显著降低程序的执行速度。事实上,这就是惰性评估可能造成问题的最主要原因。
此外,如果最终结果值确实被使用了,那么就不会节省任何计算量;相反,会为构建 thunk 付出一些轻微的开销(常数因子)。然而,这并不是程序员在大多数情况下应该处理的开销;应该考虑更重要的因素,这些因素可能会带来更大的改进;此外,像 GHC 这样的优化 Haskell 编译器可以执行“严格性分析”并消除这种轻微的开销。
此页面是 一个存根。您可以通过扩展它来帮助Haskell。 |