Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么懒惰与引用透明性相匹配?_Haskell_Lazy Evaluation_Referential Transparency - Fatal编程技术网

Haskell 为什么懒惰与引用透明性相匹配?

Haskell 为什么懒惰与引用透明性相匹配?,haskell,lazy-evaluation,referential-transparency,Haskell,Lazy Evaluation,Referential Transparency,我在读一篇哈斯克尔教程(向你学习哈斯克尔),作者在其中说,懒惰与引用的透明性是相辅相成的。经过更多的阅读和搜索,我仍然不明白为什么。请注意,我确实理解引用透明性和懒惰的好处,但正是它们一起困扰着我 两者结合有什么特别的好处吗 或者作者只是想说它们都很好,并且表达得含糊不清?引用透明性意味着函数在给定相同输入的情况下总是返回相同的输出。因此,if与函数是惰性函数还是严格函数无关。lazy函数将在将来的某个未知时间计算其输出,但由于引用透明性,可以保证给定输入的输出始终相同 因此,在某种程度上,引用

我在读一篇哈斯克尔教程(向你学习哈斯克尔),作者在其中说,懒惰与引用的透明性是相辅相成的。经过更多的阅读和搜索,我仍然不明白为什么。请注意,我确实理解引用透明性和懒惰的好处,但正是它们一起困扰着我

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


或者作者只是想说它们都很好,并且表达得含糊不清?

引用透明性意味着函数在给定相同输入的情况下总是返回相同的输出。因此,if与函数是惰性函数还是严格函数无关。lazy函数将在将来的某个未知时间计算其输出,但由于引用透明性,可以保证给定输入的输出始终相同


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

这真的很容易。非严格(如懒惰)评估意味着任务可以推迟。但是为了推迟一些事情,你最好确定你以后会得到和现在一样的结果,这就是引用透明性。考虑这个命令性的java代码:

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

现在,惰性语言会推迟第一行的求值,因为第三行只需要start。因此结果将为0(或非常接近)。也许那不是你想要的。出现该故障的原因可能是System.currentTimeMillis是引用透明的。在这种情况下,如果它是一个“数学意义上”的函数,比如sin或ln,它是引用透明的。

考虑一下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

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

非常好的例子。当然,在Haskell中也有可能破坏引用的透明性,尽管通常会有警告标志。@John:你是说使用原始内容还是
unsafePerformIO
?如果使用不当,这些被认为是有害的。无法想象另一种方式。@fuzzxl,这正是我的意思,
safe
前缀就是警告。另一种方法是将指针包装到ByteString,然后修改指针。@John:请注意,
unsafePerformIO
(以及名称中包含
unsafe
的所有其他内容)不是Haskell标准的一部分,因此实际上不能破坏“纯”Haskell中的引用透明性(这与实际无关)。@sepp2k,虽然这可能是真的,但在哈斯凯尔98中做坏事仍然是可能的。看见正如我所理解的,虽然你没有违反RT,但你确实违反了因果关系。两者都不令人满意,“状态只在第三行中需要”。严格来说,这不是事实。运行第二条线路需要询问系统当前时间的副作用;它属于
IO a
类型,而不是
a
。runBenchmarkFunction是类似的类型,为了同时运行这两个函数,您必须将它们与一些确保操作按顺序执行的函数结合起来,如Haskell中的
>
。所以你真的在写
currentTime>=\st->runBenchmarkFunction>>currentTime>=\end->putStrLn“它花了”++(show$end-st)++“秒”
。很明显,第二行依赖于第一行,所以它都可以工作。@jrockway:我在这里使用一种虚构的语言,你可以称之为“lazy Java”,作为一个非常粗糙和简单的例子来解释惰性和引用透明性之间的联系。如何在Haskell中解决这个问题是一个完全不同的问题。请注意,Haskell的“单子之路”不是唯一的可能性,例如Clean使用其类型系统来处理此问题。问题标记为“Haskell”。但是,如果你能想象正确的语义,你所写的内容在引用上是完全透明的。如果你想象其他语义学,那就不是了。但是这里的关键词是“想象”。我会选择一个不同的措辞:为了防止令人不快的惊喜,最好是懒惰的表达是指代透明的。这与其说是一件好事,不如说是一种需要。