另外:是不是你的算法只是计算像div n (minimum [a,b,c])
?
正如您所指出的,参数a,b和c不会改变,所以首先重写函数以将参数n
放在最后。
如果你决定使用一个列表来memoize的函数值它需要 一点点的关心,以确保GHC将保存映射表:
import Debug.Trace
maxCuts' :: Int -> Int -> Int -> Int -> Int
maxCuts' a b c n = memoized_go n
where
memoized_go n
| n < 0 = -10000
| otherwise = mapped_list !! n
mapped_list = map go [0..]
go n | trace msg False = undefined
where msg = "go called for " ++ show n
go 0 = 0
go n = maximum [amax, bmax, cmax]
where
amax = 1 + memoized_go (n-a)
bmax = 1 + memoized_go (n-b)
cmax = 1 + memoized_go (n-c)
test1 = print $ maxCuts' 1 2 3 10
注定义的循环依赖:memoized_go
取决于mapped_list
这取决于go
这取决于memozied_go
。
由于列表只允许非负数索引,因此n < 0
必须是 以独立的警戒模式处理。
trace
调用显示go
仅在每个值为n
时调用一次。 例如,考虑尝试这样做没有定义mapped_list
:
maxCuts2 :: Int -> Int -> Int -> Int -> Int
maxCuts2 a b c n = memoized_go n
where
memoized_go n
| n < 0 = -10000
| otherwise = (map go [0..]) !! n
-- mapped_list = map go [0..]
go n | trace msg False = undefined
where msg = "go called for " ++ show n
go 0 = 0
go n = maximum [amax, bmax, cmax]
where
amax = 1 + memoized_go (n-a)
bmax = 1 + memoized_go (n-b)
cmax = 1 + memoized_go (n-c)
test2 = print $ maxCuts2 1 2 3 11
运行test2
显示go
被调用的n
相同的值多次。
更新
为了避免产生大的未计算的thunk,我会用BangPatterns 为amax
,bmax
和cmax
:
{-# LANGUAGE BangPatterns #-}
maxCuts' ... =
...
where
!amax = 1 + ...
!bmax = 1 + ...
!cmax = 1 + ...
做的仅仅是uncurry功能所以最简单的事情,实际上,只有一个参数:'maxCuts ::(Int,Int,Int,Int) - > Int' – user2297560