假设有人将这个简单的Python代码翻译成Haskell:
def important_astrological_calculation(digits):
# Get the first 1000000 digits of Pi!
lucky_numbers = calculate_first_digits_of_pi(1000000)
return digits in lucky_numbers
Run Code Online (Sandbox Code Playgroud)
Haskell版本:
importantAstrologicalCalculation digits =
isInfixOf digits luckyNumbers
where
luckyNumbers = calculateFirstDigitsOfPi 1000000
Run Code Online (Sandbox Code Playgroud)
在使用Haskell版本之后,程序员惊讶地发现他的Haskell版本"泄漏"内存 - 在第一次调用他的函数之后,luckyNumbers
永远不会被释放.这令人不安,因为该程序包含一些更类似的功能,并且所有这些功能所消耗的内存都非常重要.
是否有一种简单而优雅的方式使程序"忘记" luckyNumbers
?
Don*_*art 21
在这种情况下,您的pidigits列表是一个常量(或"常量应用形式"),GHC可能会将其浮出,计算一次,并在使用中共享.如果没有对CAF的引用,它将被垃圾收集.
现在,通常,如果您想要重新计算某些内容,请将其转换为函数(例如,通过添加虚拟()
参数).关于CAF的链接问题中的示例:如何在Haskell中使CAF不是CAF?
解决这个问题的三种方法(基于这篇博客文章)
\nINLINE
编译指示添加{-# INLINE luckyNumbers #-}
另一个importantAstrologicalCalculation
。
这将使单独的调用彼此独立,每个调用都使用自己的副本,该副本luckyNumbers
会迭代一次并立即由 GC 收集。
优点:
\n缺点:
\n-fno-full-laziness
GHC 标志luckyNumbers
用虚拟 lambda 包裹并使用-fno-full-laziness
:
{-# OPTIONS -fno-full-laziness #-}\n\nluckyNumbers _ = calculateFirstDigitsOfPi 1000000\n
Run Code Online (Sandbox Code Playgroud)\n如果没有该标志,GHC 可能会注意到 in 中的表达式luckyNumbers
不使用其参数,因此它可能会将其浮出并共享它。
优点:
\n缺点:
\n-fno-full-laziness
阿朗佐·丘奇 (Alonzo Church) 著名地发现数据可以在函数中编码,我们可以使用它来避免创建可以共享的数据结构。
\nluckyNumbers
可以将其制作为折叠 pi 数字的函数,而不是数据结构。
优点:
\n缺点:
\n