【问题标题】:Haskell method is too slowHaskell方法太慢了
【发布时间】:2013-12-13 00:12:25
【问题描述】:

我在 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

我测试过,但是这个方法很慢。如果我用 25 个包含 3 个项目的内部列表来调用它,则需要一分钟来计算 maxSumme。这不正常不是吗?我一定犯了一个错误,但我找不到它。如何优化我的方法?有没有更快的方法来做到这一点?

编辑:我认为发现了错误。我确信它是maxSumme l then maxSumme l。我每次都经常循环遍历列表,这需要很长时间。但实际上我不知道如何避免这种情况。

【问题讨论】:

  • let 提升maxSumme l 将时间复杂度从指数降低到线性。 CSE 在惰性语言中并不总是可以的,但在这种情况下是可以的。
  • 我是 Haskell 的新手。左举和 CSE 是什么意思?如果能改成线性函数就好了
  • 他的意思是将重复 subSumme x 的代码包装在 let ssx = subSumme x in ... 中(并将 subSumme x 替换为 ssx)。这就像以某种方式定义一个新变量。 maxSumme l 也是如此。 CSE 的意思是“公共子表达式消除”。如果编译器会意识到这些表达式是相同的,它可能会完成我们刚才描述的操作并优化代码中的 hell,但由于某种原因它没有(也许并不总是好的,正如菲利普建议的那样)。
  • CSE 会导致更多的共享,从而恶化渐近空间效率。因此,由于这个原因,GHC 比其他激进的生产质量编译器执行更少的 CSE,尽管它可能在处理此类情况方面做得更好。
  • @Guido 我认为问题不在于未共享的subSumme,而是未共享的maxSumme。离开subSumme unshared 费用翻倍;离开maxSumme unshared 会使递归调用的次数加倍,这会导致递归列表长度的指数成本。

标签: haskell optimization


【解决方案1】:

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

maxSumme xs = maximum $ map subSumme xs

如果你不能使用maximum,你需要弄清楚如何自己实现它=P


为了解释$ 运算符,它的意思是总是在左边运行之前的所有内容。它使一个表达式像

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

进入

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

基本上,它只是为了在很多情况下消除对括号的需求。

【讨论】:

  • 谢谢你,效果很好!我知道最大函数,但我不知道 $ 运算符。它有什么用?
  • @Cilenco:它几乎什么都不做(实际上是($) = id!),但被解析为低优先级的运算符。将它简单地阅读为围绕需要它们的所有内容的括号,无论是左侧还是右侧。在这种情况下,maximum (map subSumme xs).
  • subSumme 实际上与 Pr​​elude 中的标准 sum 函数相同,只是平台的版本优化得更好。所以@bheklilr 的解决方案可以进一步改进为maxSumme xs = maximum $ map sum xs
  • @Guido 我的论点的哪一部分是错误的?如果有问题我想解决它。我在帖子开头提到,OP 弄清楚了 为什么 他的解决方案很慢,并提供了一个更快的替代解决方案。
猜你喜欢
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 2012-08-21
  • 2017-01-28
  • 2022-10-15
  • 2012-01-09
  • 2013-03-10
  • 2014-06-07
相关资源
最近更新 更多