如何在Haskell(GHC)中控制自动记忆



这是一个小程序,可以打印 40 个斐波那契数三次 -

module Main where
fib :: Int -> Int
fib 1 = 1
fib 2 = 1
fib n = fib (n-1) + fib (n-2)
main :: IO ()
main = run >> run >> run
  where
    run = mapM_ (print . fib) [1..40]

如果我用 ghc Main.hs 编译它,那么 GHC 保存了 "run" 的计算部分,因此执行 run 三次与运行一次所需的时间大致相同。这真是个惊喜!我的印象是,一元效应不会像这样自动记忆。

另外,如果我用ghc -O2 Main.hs编译它,那么记忆就会丢失。(至少在我的机器上使用 ghc 7.10.3)

我如何预测何时要记住某些内容?某处是否有一些记录在案的经验法则?这如何与unsafePerformIO之类的玩法?

这里run是一个常量表达式。因此,像任何其他常量表达式一样,它只被计算一次。哦,它编码的 I/O 操作执行三次,但表达式(或者更确切地说,它的子表达式)只计算一次。

我的猜测(这只是一个猜测)是不命名它可能会导致每次都重新评估它。如在

main = do
  mapM_ (print . fib) [1..40]
  mapM_ (print . fib) [1..40]
  mapM_ (print . fib) [1..40]

可能会多次评估它。但我不是100%确定。

现在,如果run是一个函数

main = run 40 >> run 40 >> run 40
  where
    run n = mapM_ (print . fibs) [1..n]

那么它可能会多次评估。我认为 GHC 会避免像这样保留任意函数调用的结果。

最新更新