添加列表中的所有项目,然后从0重新启动

时间:2013-12-14 14:31:54

标签: haskell

在Haskell中是否可以编写一个函数来汇总整数列表中的所有项目,如果列表中间的总和小于0,那么重新启动加起来为0.我的意思是这样的:

[2,5,-6,-2,8,4]

2 + 5 =  7
7 - 6 =  1
1 - 2 = -1     restart here because we are under 0
0 + 8 =  8
8 + 4 = 12

function return 12

当然我知道我可以使用以下代码添加列表中的所有项目:

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

但是我不知道如果一个总和小于0我怎么能重新启动这个函数。对于那个或那个在功能编码语言中不可能的想法,因为我们没有真正的变量或其他什么?

2 个答案:

答案 0 :(得分:3)

让我使用scanl来显示正在发生的事情,然后使用foldl来获取实际结果。

首先让我们尝试添加列表的所有元素:

Prelude> scanl (+) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]

这相当于:

Prelude> scanl (\a b -> a+b) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]

为了避免负面的中间数,你可以改变它:

Prelude> scanl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
[0,2,7,1,0,8,12]

要仅获取实际结果,请将scanl替换为foldl

Prelude> foldl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
12

答案 1 :(得分:2)

很有可能,你使用累加器变量。

sumPos xs = go 0 xs where
  go acc [] = acc
  go acc (x:xs) = go (max (acc + x) 0) xs

这可以通过内置的递归函数来解决,例如foldl'非常好。

sumPos = foldl' step 0 where
  step x acc = max 0 (x + acc)

如果您像某些人一样定义foldl' (max 0 .: (+)) 0,则甚至可以(.:) = (.).(.)