为什么懒惰与参考透明度相吻合?

时间:2010-10-05 14:26:12

标签: haskell lazy-evaluation referential-transparency

我正在阅读Haskell教程(Learn You a Haskell),其中作者说懒惰与参考透明度相得益彰。经过更多的阅读和一些搜索,我仍然不明白为什么。请注意,我确实理解参考透明度和懒惰的优点,但是它们在一起令我感到不安。

两者结合有什么特别的好处吗?

或者也许作者只是想说他们都很高兴并且表达得很含糊?

3 个答案:

答案 0 :(得分:11)

这真的很容易。非严格(例如懒惰)评估意味着可以推迟任务。但是为了推迟某些事情,你更好地确保你得到的结果与你现在得到的结果相同,这就是参考透明度。考虑这个命令式Java代码:

long start = System.currentTimeMillis(); //get the start time
runBenchmarkFunction();
System.out.println("Run took " + (System.currentTimeMillis() - start) + " ms"); 

现在一种懒惰的语言会推迟第一行的评估,因为只需要在第三行开始。所以结果将是0(或非常接近它)。可能这不是你想要的。造成这种麻烦的原因是System.currentTimeMillis 不是参照透明。如果它是像sin或ln这样的“数学意义”中的函数,那么你就不会有任何问题, 引用透明。

答案 1 :(得分:5)

参照透明度意味着在给定相同输入的情况下,函数将始终返回相同的输出。因此,如果函数是惰性或严格则无关紧要。惰性函数将在​​未来某个未知时间计算其输出,但由于参考透明度,您可以保证输出对于给定输入始终相同。

因此,在某种程度上,引用透明性可确保惰性函数的正确性。

答案 2 :(得分:4)

考虑这个Python代码,其中使用生成器来懒惰地计算无限序列。它没有引用透明性,因为它使用了全局状态,因此生成器的调用者无法确定它们获得的结果是否没有受到其他事件的影响。

foo = 0

def foo_sequence():
    global foo
    while True:
        foo += 1
        yield foo

>>> generator = foo_sequence()
>>> generator.next()
1
>>> generator.next()
2
>>> foo = 5
>>> generator.next()
6

在这种情况下,调用者更愿意以原子方式生成整个序列,以防止此类事件发生。因此,缺乏参照透明度(在这个人为的例子中)使得懒惰没有吸引力。