Haskell方法太慢了
我在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
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