另外:是不是你的算法只是計算像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