Haskell - 在列表中累计的总和

时间:2018-01-23 12:12:28

标签: list haskell functional-programming cumulative-sum

我需要创建或知道Haskell中是否有一个允许您从列表中添加项目的函数。所以,例如:

cumulativeAmount :: [Integer] -> [Integer]

cumulativeAmount [1,2,5,8,8,0,4,2] = [1,3,8,16,24,24,28,30]

cumulativeAmount [1,4,7,0,5] = [1, 1+4, 1+4+7, 1+4+7+0, 1+4+7+0+5] = [1,5,12,12,17]

我尝试使用mapscanl功能,但我没有得到我想要的东西,因为我添加了所有元素。

3 个答案:

答案 0 :(得分:9)

这正是scanl1 :: (a -> a -> a) -> [a] -> [a]的目的:

Prelude> scanl1 (+) [1,2,5,8,8,0,4,2]
[1,3,8,16,24,24,28,30]

scanl1将函数f :: a -> a -> a(此处为(+))和a列表作为输入。它构造一个列表,其中第一个项目是列表的第一个项目。这是累加器的第一个值。然后对于每个值,通过使用累加器和列表的下一个值调用f来更新累加器,然后生成此项。

因此,如果scal1 (+) [1,2,5]我们发出的第一个项目是1,我们还会将累加器设置为1。下一项是2,因此我们调用(+) 1 23),这是结果和新累加器,接下来我们调用(+) ((+) 1 2) 58 1}})等。

但我认为这更好,作为使用递归的练习。就像之前我们使用累加器一样。我们可以通过引入一个额外的函数来实现它,其中累加器是我们通过递归调用(和更新)的函数。所以在这种情况下它看起来像:

cumulativeAmount :: [Integer] -> [Integer]
cumulativeAmount [] = ...
cumulativeAmount (x:xs) = go x xs
    where go x xs = ...

所以这里gox)的第一个参数是累加器。我把它留作练习用递归来实现它。

答案 1 :(得分:4)

使用累加器怎么样:

cumulativeAmount :: (Num a) => [a] -> [a]
cumulativeAmount xs = go xs 0
    where go [] acc = []
          go (x:xs) acc = (acc+x) : go xs (acc+x)

其工作原理如下:

*Main> cumulativeAmount [1,2,5,8,8,0,4,2]
[1,3,8,16,24,24,28,30]

上面的代码保持状态变量acc,以便在遇到新数字时累积总和,并将新总和添加到结果列表中。

现在一个很好的练习就是用更高阶函数替换上面的代码。

答案 2 :(得分:3)

在我的头顶,你可以用列表理解来解决这个问题,如下:

cumulativeAmount xs = [ sum $ take x xs | x <- [1..length xs] ]