如何强制在Haskell中立即调用函数?

时间:2015-04-25 03:28:20

标签: haskell lazy-evaluation memoization

这是我的代码:

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?

2 个答案:

答案 0 :(得分:9)

问题在于,为每个参数值<select> <optgroup label="Swedish Cars"> <option value="volvo">Volvo</option> <option value="saab">Saab</option> </optgroup> </select> 等创建了memotable,而不是为整个foo 0创建了memotable。然后,从foo到下一个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

BTW我发现以下编写方式比使用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)

答案 1 :(得分:6)

像这样:

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