Haskell中多参数函数中单个参数的记忆

Haskell中多参数函数中单个参数的记忆,haskell,recursion,Haskell,Recursion,我正在解决问题,并且我的当前解决方案超过了时间限制。我相信解决我问题的办法是记忆。但是,我不了解记录的备忘录解决方案 这是我当前解决方案中的主要功能 maxCuts :: Int -> Int -> Int -> Int -> Int maxCuts n a b c | n == 0 = 0 | n < 0 = -10000 | otherwise = max (max amax bmax) cmax where

我正在解决问题,并且我的当前解决方案超过了时间限制。我相信解决我问题的办法是记忆。但是,我不了解记录的备忘录解决方案

这是我当前解决方案中的主要功能

maxCuts :: Int -> Int -> Int -> Int -> Int
maxCuts n a b c  
    | n == 0    = 0
    | n < 0     = -10000
    | otherwise = max (max amax bmax) cmax
    where 
        amax = 1 + maxCuts (n - a) a b c
        bmax = 1 + maxCuts (n - b) a b c
        cmax = 1 + maxCuts (n - c) a b c
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts(n-a)a b c
bmax=1+maxCuts(n-b)a b c
cmax=1+maxCuts(n-c)a b c

如果a b和c相对于n较小,则此函数运行时间过长。我只是复制他们用于阶乘函数的解决方案,但该函数只接受一个参数。我有四个参数,但我只想在第一个参数
n
上键入memorization。请注意,
a
b
c
在递归调用中不会更改

像这样重写函数定义:

 maxCuts :: Int -> Int -> Int -> Int -> Int
 maxCuts n a b c = maxCuts' n where
     maxCuts' n
          | n == 0    = 0
          | n < 0     = -10000
          | otherwise = max (max amax bmax) cmax
            where 
               amax = 1 + maxCuts' (n - a)  
               bmax = 1 + maxCuts' (n - b) 
               cmax = 1 + maxCuts' (n - c)
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c=maxCuts'n其中
麦克斯库茨酒店
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts'(n-a)
bmax=1+maxCuts'(n-b)
cmax=1+maxCuts'(n-c)

现在,您有了一个可以记忆的单参数函数。

重写函数定义,如下所示:

 maxCuts :: Int -> Int -> Int -> Int -> Int
 maxCuts n a b c = maxCuts' n where
     maxCuts' n
          | n == 0    = 0
          | n < 0     = -10000
          | otherwise = max (max amax bmax) cmax
            where 
               amax = 1 + maxCuts' (n - a)  
               bmax = 1 + maxCuts' (n - b) 
               cmax = 1 + maxCuts' (n - c)
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c=maxCuts'n其中
麦克斯库茨酒店
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts'(n-a)
bmax=1+maxCuts'(n-b)
cmax=1+maxCuts'(n-c)

现在您有了一个可以记忆的单参数函数。

旁白:您的算法不就是在计算类似于
divn(最小[a,b,c])的东西吗

正如您所指出的,参数a、b和c不会改变,因此首先重写函数,将参数
n
放在末尾

如果您决定使用列表来记忆所需的函数值 稍微注意确保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
运行
test2
显示对
n
的相同值调用了多次
go

更新

为了避免创建大型未评估的Thunk,我将使用BangPatterns 对于
amax
bmax
cmax

{-# LANGUAGE BangPatterns #-}

maxCuts' ... =
  ...
  where
    !amax = 1 + ...
    !bmax = 1 + ...
    !cmax = 1 + ...

旁白:你的算法不就是在计算类似于
divn(最小[a,b,c])的东西吗

正如您所指出的,参数a、b和c不会改变,因此首先重写函数,将参数
n
放在末尾

如果您决定使用列表来记忆所需的函数值 稍微注意确保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
运行
test2
显示对
n
的相同值调用了多次
go

更新

为了避免创建大型未评估的Thunk,我将使用BangPatterns 对于
amax
bmax
cmax

{-# LANGUAGE BangPatterns #-}

maxCuts' ... =
  ...
  where
    !amax = 1 + ...
    !bmax = 1 + ...
    !cmax = 1 + ...

最简单的方法就是取消函数的rry,所以实际上只有一个参数:
maxCuts::(Int,Int,Int,Int)->Int
最简单的方法就是取消函数的rry,所以实际上只有一个参数:
maxCuts::(Int,Int,Int,Int)->Int