2017-10-20 67 views
1

我是一个Haskell初学者,哈斯克尔递归并添加到列表

我有一个函数

func :: Num a => [a] -> [a] 
func [] = [] 
func (x:xs) = x + func xs 

每个递归我想要的价值附加到了我的输出列表。该函数将对列表中的连续索引进行求和,以使输入[1, 2, 3, 4]产生[1, 3, 6, 10]

如何将每次生成的值附加到我的列表中?

+0

你忘了问一个问题。但是,是的,你需要一个停止条件(基本情况) –

+0

我现在编辑 –

+1

'0'不是一个列表。 – melpomene

回答

3

这里你的问题不是如何追加,而是如何计算第一个值。每个项目都需要用它自身的总和代替它之前的所有项目。

下面是做到这一点的一种方法:

Prelude> func (x:xs) = x:map (+ x) (func xs); func [] = [] 
Prelude> func [1, 2, 3, 4] 
[1,3,6,10] 

这是如何工作的?我们给出了一个以元素x开头的列表,其余元素xs。我们希望递归地将算法应用于xs后,将xs中的每个项目递增x

这是x:map (+ x) (func xs)所做的。它读作为“在func xs中通过x的增量映射每个元素的结果”前面加上x“。


例如,对于[1, 2, 3, 4],我们希望将1添加到将算法递归应用到[2, 3, 4],然后预先计算的结果的每个成员中。对于[2, 3, 4],我们希望2为...至[3, 4]。依此类推,直到最终为[4],我们希望4被添加并应用到[]算法的结果之前。

这就是我们的基例(func [] = [])踢入的位置:该算法被定义为使其返回一个空列表不变。因此func [4][4],func [3, 4][3, 7],并且您不断递增和前置,直到您获得[1,3,6,10]

+0

你能解释这是如何工作的吗? –

+1

@JamesHamish当然,我会扩大答案。我应该提到,更常用的方法是'scanl',如其他答案所示,所以您可能想要使用/接受该方法。 –

4

我认为在这种特殊情况下,你可以使用scanl1像:

scanl1 (+) [1,2,3,4] -- [1,3,6,10] 
0

当遍历列表,我们经常使用褶皱,这正是该列表缩减为特定值的方式。

还有另一种类型的操作,这是收集沿途所有结果倍,这就是所谓的一个scan(从docs):

scanl     = scanlGo 
    where 
    scanlGo   :: (b -> a -> b) -> b -> [a] -> [b] 
    scanlGo f q ls = q : (case ls of 
           [] -> [] 
           x:xs -> scanlGo f (f q x) xs) 

所以扫描有三个参数:一个函数它接受两个值并返回一个值,一个初始值和一个值列表。

扫描将返回一个列表。

因此,您需要的是一个函数,它接受两个值并返回与第一个相同类型的东西(如果两者都相同,则可以)。二进制加法将在这里工作:+

您还需要一个值(b,这是我们函数的第二个参数),而0是整数加法的标识,所以我们应该使用它。

最后,我们通过您的列表来获得结果。

试图弄清楚如何写作为折叠功能,然后作为扫描,你会发现答案。