我正在尝试重新学习Haskell,经过多年的努力而忘记了一切,我发现自己仍然困惑于 memoization 。特别是,我正在尝试编写一个程序来生成D[n]
个n
个对象的紊乱数量(在其原始位置没有项目的排列);数字D[n]
可以由D[1]=0
,D[2]=1
,D[n]=(n-1)(D[n-1]+D[n-2])
递归定义。
这样可行:
der :: Int -> Integer
der n = lder !! n
where lder = 1 : 0 : zipWith3 (\n d1 d2 -> n * (d1+d2)) [1..] lder (tail lder)
就像这样(因为需要三个功能而有点笨拙):
nder :: Int -> Integer
nder n = nderTab !! n
nderTab :: [Integer]
nderTab = [nderCalc n | n <- [0..]]
nderCalc :: Int -> Integer
nderCalc n
| n == 0 = toInteger 1
| n == 1 = toInteger 0
| otherwise = toInteger (n-1) * (nder (n-1) + nder (n-2))
但这不是:
nders :: Int -> Integer
nders n = (map der [0 ..]) !! n
where der 0 = 1
der 1 = 0
der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
您最后会将此识别为标准记忆斐波纳契数函数的副本。我的函数有效,但没有记忆,因为它挂起大于30的值。另外,如果我写这个函数只对大于或等于1的值进行操作:
nders :: Int -> Integer
nders n = (map der [1 ..]) !! n
where der 1 = 0
der 2 = 1
der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
根本不起作用。我很想知道这两个函数有什么问题。
答案 0 :(得分:2)
使用
nders :: Int -> Integer
nders n = (map der [0 ..]) !! n
where der 0 = 1
der 1 = 0
der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)
map der [0..]
部分将针对nders
的任何应用进行重新计算,尤其包括der
中的递归调用。
你可以移出制表的定义,使它(语法上)不依赖于n
,这应该做正确的事情:
nders :: Int -> Integer
nders = (memoized !!)
where
memoized = map der [0 ..]
der 0 = 1
der 1 = 0
der n = (nders (n-2) + nders (n-1)) * toInteger (n-1)