我需要创建或知道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]
我尝试使用map
和scanl
功能,但我没有得到我想要的东西,因为我添加了所有元素。
答案 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 2
(3
),这是结果和新累加器,接下来我们调用(+) ((+) 1 2) 5
(8
1}})等。
但我认为这更好,作为使用递归的练习。就像之前我们使用累加器一样。我们可以通过引入一个额外的函数来实现它,其中累加器是我们通过递归调用(和更新)的函数。所以在这种情况下它看起来像:
cumulativeAmount :: [Integer] -> [Integer]
cumulativeAmount [] = ...
cumulativeAmount (x:xs) = go x xs
where go x xs = ...
所以这里go
(x
)的第一个参数是累加器。我把它留作练习用递归来实现它。
答案 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] ]