Haskell中多参数函数的记忆

Joh*_*n G 8 haskell memoization ghc

使用记忆化的函数下面的例子是提出了关于此页:

memoized_fib :: Int -> Integer
memoized_fib = (map fib [0..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)
Run Code Online (Sandbox Code Playgroud)

但是,如果我们想要记住多参数功能怎么办?例如,我们可以创建一个'乘以斐波那契'来定义f(m,n) = m*f(m,n-2) + m*f(m,n-1).我修改了上面这个'乘法斐波那契'函数的代码,如下所示:

mult_fib :: Integer -> Int -> Integer
mult_fib mult = (map (m_fib mult) [0..] !!)
    where m_fib _ 0 = 0
          m_fib _ 1 = 1
          m_fib m n = m*(mult_fib m (n-2)) + m*(mult_fib m (n-1))
Run Code Online (Sandbox Code Playgroud)

修改后的函数的运行时是指数的,即使原始是线性的.为什么这种技术在第二种情况下不起作用?另外,如何修改函数以使用memoization(不使用库函数)?

lef*_*out 8

正如Vitus所说,在你的例子中可以很简单地完成.正确实施这个想法:

multFib :: Integer -> Int -> Integer
multFib mult = multFib'
    where multFib' = (map m_fib [0..] !!)
          m_fib 0 = 0
          m_fib 1 = 1
          m_fib n = mult * (multFib' $ n-2) + mult * (multFib' $ n-1)
Run Code Online (Sandbox Code Playgroud)

但是,这里的备忘录并不像你的例子那样强大:它只能用于优化单个函数调用,但结果列表通常不会在multFib具有相同mult参数的后续调用之间存储.

要实现这一点,您需要在两个参数上索引memmentation查找,如下所示:

multFibFullMemo :: Int -> Int -> Integer
multFibFullMemo = \mult n -> memo_table !! mult !! n
 where memo_table = [ [m_fib mult' n' | n'<-[0..]] | mult' <- [0..] ]
       m_fib _ 0 = 0
       m_fib _ 1 = 1
       m_fib mult n = m * (multFibFullMemo mult $ n-2) + m * (multFibFullMemo mult $ n-1)
        where m = toInteger mult
Run Code Online (Sandbox Code Playgroud)

很明显,如果您打算将它用于更大的mult参数,这将无效:它总是需要跳到具有该数字长度的列表.

MemoTrie等图书馆提供了更加复杂的备忘录,不会受到此类问题的影响.

  • 根据经验,GHC将在每次输入封闭的lambda时最多评估一次给定的表达式.如果你离开lambda并稍后再输入相同的值,表达式可以(通常会)重新计算. (3认同)
  • 无论如何,因为看起来我的两个编辑被合并在一起并且只剩下最后一个编辑消息:原始列表理解在`\ mult n - >`lambda内部,因此每次调用`multFibFullMemo`时都会重新计算. (2认同)