Haskell和懒惰:将常用值存储为成员还是只是动态计算?

时间:2013-04-09 17:00:49

标签: haskell

在Haskell中,关于它的惰性,最好将经常计算的值存储为标准的非扩展Haskell中的数据成员,还是安全的,不这样做。

为了更好地理解我的意思,举个例子:

data Image = Image { size :: Int, inverse_size :: RealFrac }

new_image size = Image { size = size, inverse_size = 1.0 / fromIntegral size }

或者我只是声明它被使用的地方,假设经常调用function

data Image = Image { size :: Int } -- no tainting

something (Image size) =
    let inverse_size = 1.0 / fromIntegral size -- possibly make a function of it
    in ...

作为一种懒惰的语言,来自C ++模板元编程,我不知道Haskell会记住这样的计算有多少。

这是否会产生任何差异,运行时速度和存储方式?

1 个答案:

答案 0 :(得分:2)

非规范化 - 性能权衡不是Haskell特有的。如果您作为示例提供的Image类型与实际情况接近,并且您使用大量Image s进行操作,则通过预先计算inverse_size几乎无法提高性能,因为您保存1个操作,将值放在FPU堆栈上,1个浮点除法,代价是内存增加1个额外负载(如果size函数中使用了somethinginverse_size),和x2-3内存使用量增加。这不是一个伟大的成就。

任何方式,为了给inverse_size一个机会你应该确保这个字段是严格的:

data Image = Image { size :: !Int, inverse_size :: !Float }

否则这种预先计算肯定是毫无意义的。

如果你想知道GHC编译器本身是否优化了这些东西,那么答案是:GHC能够在一个函数中浮动重复计算(或者如果它们被内联则在几个函数中嵌套(通过调用嵌套)),但是因为它赢了“在您的数据结构中创建一个新字段。