出于好奇,我制作了一个简单的脚本来检查在Haskell中构建列表的速度和内存效率:
wasteMem :: Int -> [Int]
wasteMem 0 = [199]
wasteMem x = (12432483483467856487256348746328761:wasteMem (x-1))
main = do
putStrLn("hello")
putStrLn(show (wasteMem 10000000000000000000000000000000000))
奇怪的是,当我尝试这个时,它没有耗尽内存或堆栈空间,它只打印[199],与运行wasteMem 0相同。它甚至不打印错误消息..为什么?在ghci中输入这个大数字就会输出数字,所以我不认为这是一个舍入或读数错误。
答案 0 :(得分:15)
您的程序使用的数字大于maxBound :: Int32
。这意味着它在不同平台上的行为会有所不同。对于GHC,x86_64 Int
是64位(否则为32位,但Haskell报告仅承诺29位)。这意味着你的荒谬大值(1x10 ^ 34)对我来说表示为4003012203950112768
而对于32位大家来说则为0:
GHCI> 10000000000000000000000000000000000 :: Int
4003012203950112768
GHCI> 10000000000000000000000000000000000 :: Data.Int.Int32
0
这可以通过使用固定大小类型(例如:来自Data.Word或Data.Int)或使用整数来使平台独立。
所有这一切,这是一个开始时考虑不周的测试。 Haskell是懒惰的,因此wastedMem n
对任何值n
消耗的内存量都很小 - 它只是thunk。一旦你试图显示这个结果,它将一次一个地从列表中获取元素 - 首先生成"[12432483483467856487256348746328761,
并将列表的其余部分保留为thunk。在第二个值被考虑之前,第一个值可以被垃圾收集(一个恒定空间程序)。
答案 1 :(得分:3)
添加到Thomas的答案,如果你真的想浪费空间,你必须在列表上执行操作,这需要立即在内存中的整个列表。一个这样的操作是排序:
print . sort . wasteMem $ (2^16)
另请注意,估计列表的运行时内存使用情况几乎是不可能的。如果您想要更可预测的内存基准,请创建一个未装箱的阵列而不是列表。这也不需要任何复杂的操作来确保一切都留在内存中。索引数组中的单个元素已经确保数组至少在内存中一次。