如何在 Haskell 中强制立即调用函数?
How do I force a function to be called immediately in Haskell?
这是我的代码:
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"创建一个新的备忘录-table。我怎样才能强制 GHC 只评估 "memoFix fooMemo" 一次,这样它就不会创建超过一个 memotable?
像这样:
main = let f = foo 0 in do
print $ f 5
print $ f 5
print $ f 5
问题是 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)
这是我的代码:
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"创建一个新的备忘录-table。我怎样才能强制 GHC 只评估 "memoFix fooMemo" 一次,这样它就不会创建超过一个 memotable?
像这样:
main = let f = foo 0 in do
print $ f 5
print $ f 5
print $ f 5
问题是 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)