【问题标题】:How do I force a function to be called immediately in Haskell?如何强制在 Haskell 中立即调用函数?
【发布时间】:2015-04-25 03:28:19
【问题描述】:

这是我的代码:

import Data.Function.Memoize
import Debug.Trace

foo :: Int -> Int -> Int
foo a = memoFix fooMemo where 
    fooMemo f x = a + (trace (show x) cont) where
        cont = if x == 0 then 0 else x + f (x - 1)

main = do
    print $ foo 0 5
    print $ foo 0 5
    print $ foo 0 5

我希望它会打印出来:

3
2
1
0
6
6
6

但是,相反,它会打印:

3
2
1
0
6
3
2
1
0
6
3
2
1
0
6

换句话说,函数并没有像我预期的那样被记忆。这可能是因为每次调用“foo 0”时,都会为“foo”创建一个新的备忘录表。如何强制 GHC 只评估一次“memoFix fooMemo”,这样它就不会创建多个 memotable?

【问题讨论】:

  • Data.Function.Memoize 来自什么包?
  • @DanielWagner memoize
  • FWIW,我发现您的代码行为与您报告的行为非常不同。我认为您的实际代码可能使用3 作为最后一个参数,而不是5

标签: haskell lazy-evaluation memoization


【解决方案1】:

问题是 memotable 是为 每个 参数值、foo 0 等创建的,而不是为整个 foo 创建的。然后这些 memotables 不会从foo 的一次调用共享到下一次。解决方案是确保记住整个foo

import Data.Function.Memoize
import Debug.Trace

foo :: Int -> Int -> Int
foo = memoize foo1 where
    foo1 a = memoFix fooMemo where 
        fooMemo f x = a + (trace (show x) cont) where
            cont = if x == 0 then 0 else x + f (x - 1)

main = do
    print $ foo 0 5
    print $ foo 0 5
    print $ foo 0 5

顺便说一句,我发现以下编写方式比使用memoFix 更容易:

foo :: Int -> Int -> Int
foo = memoize2 $ \a x ->
    let cont = if x == 0 then 0 else x + foo a (x - 1)
    in a + (trace (show x) cont)

【讨论】:

    【解决方案2】:

    像这样:

    main = let f = foo 0 in do
        print $ f 5
        print $ f 5
        print $ f 5
    

    【讨论】:

      猜你喜欢
      • 2013-10-23
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-11
      相关资源
      最近更新 更多