poc*_*hen 2 performance implementation haskell callbyname
我认为它没有.
我的理由是Haskell是纯函数式编程(没有I/O Monad),如果"名称"相同,他们可以使每个"名字调用"使用相同的评估值.
我对实现细节一无所知,但我真的很感兴趣.
详细解释将非常感谢:)
顺便说一句,我试过谷歌,很难得到任何有用的东西.
首先,Haskell是一个规范,而不是一个实现; 该报告实际上并不需要使用逐个名称的评估或懒惰的评估.Haskell实现只需要是非严格的,这可以排除按值调用和类似的策略.
因此,严格(哈哈)说,评估策略不能减缓Haskell.我不确定什么可以减慢Haskell的速度,虽然显然有什么东西,否则在Haskell 98之后不会用12年的时间来获得报告的下一个版本.我的猜测是它以某种方式涉及委员会.
无论如何,"懒惰评估"指的是"按需调用"策略,这是Haskell最常见的实现选择.这与按名称调用的不同之处在于,如果在多个位置使用子表达式,则最多只评估一次子表达式.
有资格作为将要共享的子表达式的细节有点微妙,可能在某种程度上依赖于实现,但是使用GHC Haskell的示例:考虑函数cycle,它无限地重复输入列表.一个天真的实现可能是:
cycle xs = xs ++ cycle xs
Run Code Online (Sandbox Code Playgroud)
这最终效率低下,因为没有单个cycle xs表达式可以共享,因此结果列表必须在遍历时不断构造,每次分配更多内存并进行更多计算.
相比之下,实际实现如下:
cycle xs = xs' where xs' = xs ++ xs'
Run Code Online (Sandbox Code Playgroud)
这里名称xs'是递归定义的,因为它本身附加在输入列表的末尾.这个时间xs'是共享的,只评估一次; 生成的无限列表实际上是内存中的有限循环链表,并且一旦评估了整个循环,就不需要进一步的工作.
一般情况下,GHC不会为您记忆函数:给定f并且x每次使用都f x将被重新评估,除非您给结果命名并使用它.在任何一种情况下,结果值都是相同的,但性能可能会有很大差异.这主要是为了避免悲观 - GHC很容易为你记忆,但在很多情况下,这会花费大量内存来获得微小或不存在的速度.
另一方面是保留共享值; 如果你有一个计算成本非常高的数据结构,命名构造它的结果并将其传递给使用它的函数确保没有重复的工作 - 即使它被不同的线程同时使用.
你也可以用这种方式自己去做一些事情 - 如果一个数据结构计算起来很便宜并且占用大量内存,你应该避免共享对完整结构的引用,因为只要有任何东西可以保持整个事物在内存中存活可能以后再用.