当前位置:  开发笔记 > 编程语言 > 正文

Scala中的call-by-name与Haskell中的懒惰评估?

如何解决《Scala中的call-by-name与Haskell中的懒惰评估?》经验,为你挑选了1个好方法。

Haskell的懒惰评估永远不会比急切的评估采取更多的评估步骤.

另一方面,Scala的逐个名称评估可能需要比按值调用更多的评估步骤(如果短路效益大于由重复计算的成本抵消).

我认为按名称呼叫大致相当于懒惰的评估.为什么那么时间上的这种差异保证了?

我猜测也许Haskell语言指定在评估期间必须使用memoization; 但在那种情况下,为什么Scala不这样做呢?



1> Alec..:

评估策略的名称有一定的广度,但它们大致如下:

按名称调用一个参数几乎只是在调用函数时以任何(未评估的)形式替换到函数体中.这意味着它可能需要在体内多次评估.

在Scala中,您将其写为:

scala> def f(x:=> Int): Int = x + x
scala> f({ println("evaluated"); 1 })
evaluated
evaluated
2

在Haskell中,您没有内置的方法来执行此操作,但您始终可以将按名称调用值表示为类型的函数() -> a.这有点模糊,但由于参考透明度 - 你将无法像Scala一样测试它(并且编译器可能会优化掉你的"名字"部分).

按需调用(lazy ... sort)调用函数时不会计算参数,但是第一次需要.那一刻,它也被缓存了.之后,只要再次需要参数,就会查找缓存的值.

在Scala中,你没有声明你的函数参数是懒惰的,你做一个懒惰的声明:

scala> lazy x: Int = { println("evaluated"); 1 }
scala> x + x
evaluated
2

在Haskell中,这是默认情况下所有函数的工作方式.

调用函数时,按值调用(渴望,几乎每种语言都会这样做)参数被计算,即使函数最终没有使用这些参数.

在Scala中,这是默认情况下函数的工作方式.

scala> def f(x: Int): Int = x + x
scala> f({ println("evaluated"); 1 })
evaluated
2

在Haskell中,您可以在函数参数上使用bang模式强制执行此行为:

ghci> :{
ghci> f :: Int -> Int
ghci> f !x = x
ghci> :}

因此,如果需要调用(懒惰)执行或多或少的评估(作为其他策略之一),为什么要使用其他任何东西?

懒惰的评价是很难推理,除非你有引用透明,因为你需要准确地计算出,当你懒的价值进行评估.由于Scala是为与Java互操作而构建的,因此它需要支持命令式的,有效的编程.因此,在许多情况下,在Scala中使用它并不是一个好主意lazy.

此外,lazy还有一个性能开销:您需要有一个额外的间接检查以检查该值是否已经过评估.在Scala中,这会转换为更多的对象,这会给垃圾收集器带来更大的压力.

最后,有些情况下,懒惰评估会留下"空间"泄漏.例如,在Haskell中,通过将它们加在一起从右侧折叠大量数字是一个坏主意,因为Haskell会(+)在评估它们之前建立这个庞大的一系列惰性调用(实际上你只需要它有一个累加器)你在简单的环境中得到甚至空间问题的一个著名的例子就是foldrVS foldlVSfoldl'.

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有