在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会记住这样的计算有多少。
这是否会产生任何差异,运行时速度和存储方式?
答案 0 :(得分:2)
非规范化 - 性能权衡不是Haskell特有的。如果您作为示例提供的Image
类型与实际情况接近,并且您使用大量Image
s进行操作,则通过预先计算inverse_size
几乎无法提高性能,因为您保存1个操作,将值放在FPU堆栈上,1个浮点除法,代价是内存增加1个额外负载(如果size
函数中使用了something
和inverse_size
),和x2-3内存使用量增加。这不是一个伟大的成就。
任何方式,为了给inverse_size
一个机会你应该确保这个字段是严格的:
data Image = Image { size :: !Int, inverse_size :: !Float }
否则这种预先计算肯定是毫无意义的。
如果你想知道GHC编译器本身是否优化了这些东西,那么答案是:GHC能够在一个函数中浮动重复计算(或者如果它们被内联则在几个函数中嵌套(通过调用嵌套)),但是因为它赢了“在您的数据结构中创建一个新字段。