Haskell: memoization

你。 提交于 2019-12-20 05:11:03

问题


I'm trying to relearn Haskell, after many years away and forgetting everything, and I find myself still confused my memoization. In particular, I'm trying to write a program to generate the number of derangements D[n] of n objects (permutations with no item in its original place); the numbers D[n] can be defined recursively by D[1]=0, D[2]=1, D[n]=(n-1)(D[n-1]+D[n-2]).

So this works:

der :: Int -> Integer
der n = lder !! n
  where lder = 1 : 0 : zipWith3 (\n d1 d2 -> n * (d1+d2)) [1..] lder (tail lder)

as does this (which is a bit clumsy as it requires three functions):

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))

But this doesn't:

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)

You'll recognize this last as a copy of the standard memoized Fibonacci number function. My function works, but isn't memoized, as it hangs on values larger than about 30. Also, if I write this function to operate only on values greater than or equal to 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)

it doesn't work at all. I'm curious to know what's wrong with these last two functions.


回答1:


With

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)

the map der [0..] part will be recomputed for any application of nders, especially including the recursive calls in der.

You can move out the definition of the tabulation so that it doesn't (syntactically) depend on n, which should do the right thing:

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)


来源:https://stackoverflow.com/questions/34644761/haskell-memoization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!