Haskell:列表和折叠

时间:2012-09-25 04:18:15

标签: list haskell fold

我有一系列数字:0,1,3,6,10,15 ...... 基本上,你添加1,然后你添加2,然后添加3,等等。

我必须创建一个函数,在列表中返回给定数字n的这一系列数字。我想用foldl。

所以,系列5应该返回[0,1,3,6,10,15]

这是我到目前为止所做的:

eachElem n = foldl (+) 0 [0..n]

series n = [x | x <- [(eachElem 0), (eachElem 1)..(eachElem n)]]

基本上,我认为列表中的每个元素都是一个foldl操作,因此我创建了一个单独的辅助函数(eachElem)来完成此任务。

然而,它返回的列表比我想要的要大得多。

EG。系列3 =&gt; [0,1,2,3,4,5,6]什么时候应该真的返回[0,1,3,6]

为什么会这样?

7 个答案:

答案 0 :(得分:7)

scanl更适合您正在做的事情。

其类型为scanl :: (a -> b -> a) -> a -> [b] -> [a] - 其类型签名与foldl相同,但它返回增量值列表,而不仅仅是最终结果。

我会把剩下的作为锻炼给你,因为这看起来像是家庭作业。祝你好运!

答案 1 :(得分:2)

如果您坚持使用foldl,可以执行类似

的操作
series n  = reverse $ foldl f [0] [1..n]
    where f xs@(x:_) y = x+y:xs

在ghci

> series 5
[0,1,3,6,10,15]

但是foldl的问题是你无法创建无限系列。

你可以拥有像

这样的无限系列
series = 0:zipWith (+) series [1..]

然后你可以做类似

的事情
> take (5+1) series
[0,1,3,6,10,15]

我没有尝试,但您也可以使用unfoldr或类似的概念来构建列表。

答案 2 :(得分:1)

scanl是最好的,但是如果你必须使用折叠试试这个


testso :: Integral a => a -> [a]
testso n = reverse $ foldl (\acc x -> head acc + x:acc ) [0] [1,2..n] 

输出为testso 10 [0,1,3,6,10,15,21,28,36,45,55]。

答案 3 :(得分:0)

当你写[a,b..c]时,a是第一个元素,c是最后一个元素,b是步骤,它是列表中每个元素之间的间隔,如果省略它,它将是默认为1。

让我们看一下你的代码吧:

  [x | x <- [(eachElem 0), (eachElem 1)..(eachElem n)]] 
  • 在列表推导中,x将首先取值(eachElem 0)= 0
  • 然后下一个元素将是(eachElem 0)+(eachElem 1)= 1
  • 然后第i个elent将是(everyElem 0)+ i *(everyElem 1 - eachElem 0),只要该值为&lt; =(everyElem n)

因此你的结果:[0,1 ..(eachElem n)]产生[0,1,2,3 ...并且显然不是你所期望的。

正如amindfv所建议的那样,你应该看看scanl。

答案 4 :(得分:0)

您对series的定义是错误的。

[(eachElem 0), (eachElem 1)..(eachElem n)]变为[0, 1, eachElem n],实际上每个数字都会达到eachElem n

你真的想这样做:

series n = [eachElem x | x <- [0..n]]

答案 5 :(得分:0)

定义

series n = [ x | x <- [(eachElem 0)..(eachElem n)]]

错了!

例如:

因为

eachElem 0 -> 0
eachElem 3 -> 6

系列3评估为

series 3 -> [(eachElem 0)..(eachElem 3)] -> [0..6] -> [0,1,2,3,4,5,6]

你需要类似的东西

series' n = [ eachElem x | x <- [0..n]]

测试:

> let series' n = [ eachElem x | x <- [0..n]]
> let series n = [ x | x <- [(eachElem 0)..(eachElem n)]]

> series' 3
> [0,1,3,6]

> series 3
> [0,1,2,3,4,5,6]

> eachElem 0
> 0

> eachElem 3
> 6

答案 6 :(得分:0)

你可以作弊: - )

series x = foldl (\xs n -> (n*(n+1) `div` 2):xs) [] [x,(x-1)..0]