Haskell方法太慢了

Haskell方法太慢了,haskell,optimization,Haskell,Optimization,我在Haskell中编写了一个函数,如下所示: maxSumme :: [[Int]] -> Int maxSumme [] = 0 maxSumme (x:l) = if subSumme x < maxSumme l then maxSumme l else subSumme x subSumme :: [Int] -> Int subSumme [] = 0 subSumme (x:l) = x + subSumme(l) -- functi

我在Haskell中编写了一个函数,如下所示:

maxSumme :: [[Int]] -> Int
maxSumme [] = 0
maxSumme (x:l) = if subSumme x < maxSumme l then maxSumme l else subSumme x

subSumme :: [Int] -> Int
subSumme [] = 0             
subSumme (x:l) = x + subSumme(l)

-- function call
maxSumme [[7,2,4],[5,8,1],[7,9,2]] -- with 25 innerLists
maxSumme::[[Int]]->Int
maxSumme[]=0
maxSumme(x:l)=如果子Summe xInt
子摘要[]=0
子摘要(x:l)=x+子摘要(l)
--函数调用
maxSumme[[7,2,4],[5,8,1],[7,9,2]——具有25个内部列表
我测试了它,但是这个方法非常慢。如果我用一个包含25个内部列表和3个项目的列表来调用它,那么计算maxSumme需要一分钟的时间。这不正常,不是吗?我一定做了些什么​​一个错误,但我找不到。如何优化我的方法?有没有更快的方法


编辑:我想我发现了错误。我确信它是
maxSumme l,然后是maxSumme l
。每次我都会循环浏览这个列表,这需要很长时间。但实际上我不知道如何避免这种情况。

所以您已经找到了问题函数。这是因为对于每个列表,您都会多次调用
subSumme
。相反,您可以将
subSumme
映射到传递给
maxSumme
的每个列表,然后找到这些数字的最大值:

maxSumme xs = maximum $ map subSumme xs
如果您不能使用
最大值
,那么您需要弄清楚如何自己实现它=p


为了解释
$
操作符,它意味着总是先向右运行,再向左运行。它使一个表达像

f (g (h (i (j (k (l x))))))
进入

请注意,对于具有多个参数的函数,这会变得很棘手。这不会编译

map $ (1+) $ replicate 10 1
因为它和

  map ((1+) (replicate 10 1))
= map ((1+) replicate 10 1))
= map (1 + replicate 10 1)
= map (1 + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
         ^------ Can't add a number to a list!
但你可以做到

map (1+) $ replicate 10 1

基本上,在很多情况下,它所做的就是消除对括号的需要。

let
提升
maxSumme l
将时间复杂度从指数降低到线性。CSE在惰性语言中并不总是好的,但在这种情况下就是这样。我是Haskell的新手。你说左举和CSE是什么意思?如果我能把它改成一个线性函数,那就太好了。这意味着将重复
subSumme x
的代码包装在
let ssx=subSumme x in…
(并将
subSumme x
替换为
ssx
)。这就像定义了一个新的变量,某种程度上。
maxSumme l
也是如此。CSE表示“公共子表达式消除”。如果编译器意识到这些表达式是相同的,那么它就可以完成我们刚才描述的和优化的代码,但由于某些原因它没有做到(也许它并不总是像Philip所建议的那样好)。CSE会导致更多的共享,从而恶化渐进空间效率。因此,GHC的CSE比其他具有高生产质量的编译器要少,尽管它在处理此类情况时可能会做得更好。@Guido我认为问题不在于非共享的
子摘要
,而在于非共享的
最大摘要
。使未共享成本加倍;保留
maxSumme
非共享将使递归调用的数量增加一倍,这将导致递归列表的长度出现指数级的开销。谢谢,这非常有效!我知道最大值函数,但不知道$运算符。它的作用是什么?@Cilenco:它几乎什么都不做(事实上,
($)=id
!),但被解析为一个低优先级的运算符。把它简单地当作一本书,把所有需要它们的东西放在左右两边。在这种情况下,
maximum(map subSumme xs)
subSumme
实际上与前奏曲中的标准
sum
函数相同,只是平台的版本得到了更好的优化。因此@bheklillr的解决方案可以进一步改进为
maxSumme xs=maximum$map sum xs
@Guido我的参数有哪些部分是错误的?如果有问题,我想解决它。我在帖子的开头提到,OP找出了他的解决方案为什么慢,并给出了一个更快的替代解决方案。
map (1+) $ replicate 10 1