2017-09-14 24 views
2

我想使用Haskell读取列表并执行交替序列,因此从第一个元素开始添加每个其他元素并从第二个元素中减去每个其他元素。例如[1,2,3,4]将是1-2 + 3-4 = -2。我以为我已经想出了如何为特定长度的列表(我编写它来容纳空列表并列出多达4个元素长),但它没有做到我认为的那样。它只是返回列表中的第一个元素。这是我有:使用Haskell的交替系列

altSeries :: Num a => [a] -> a 
altSeries [] = 0 
altSeries (x:xs) = if length xs == 1 then x 
        else if length xs == 2 then x 
        else if length xs == 3 then (x - xs!!1 + xs!!2) 
        else (x - xs!!1 + xs!!2 - xs!!3) 

另外,如果我想能够使用任何列表大小?

+0

我不知道你怎么样测试你的代码,但它甚至不处理长度为1的列表。 – melpomene

+3

对于大多数练习,你应该忘记'长度,头部,尾部,!!'存在,并且纯粹使用模式匹配和递归。 – chi

回答

4

我认为很明显,这个解决方案没有缩放:即使你写了长度为1000的函数,它会从某人进入一个有一千个和一个元素的列表开始。

列表通常处理完成递归:我们处理列表的(或第一ķ头),并在表的尾部执行递归。此外,我们有一些基地台(可以是一个)来终止递归。

您已经提供了一个单一的基本情况:空单:

altSeries [] = 0 

如果我们进入空单,很显然,我们应该回到0。现在我们可能会问如何获得长度为1的列表:在这种情况下,列表的形状为[x]。所以在这种情况下,我们应该返回x,因为我们应该添加x,并且不能减去第二个数字。所以我们增加:

altSeries [x] = x 

现在问题是如何处理长度为两个或更多的列表。在这种情况下,该列表具有(x1:x2:t)的模式,第一个元素为x1,第二个元素为x2,其余元素为t。根据您的描述,我们应该caculate x1-x2并添加altSeries t

altSeries (x1:x2:t) = x1 - x2 + altSeries t 

这工作,因为altSeries然后将递归提取和x4,所以后来就改乘:

altSeries [x1,x2,x3,x4,x5] = x1 - x2 + altSeries [x3,x4,x5] 
          = x1 - x2 + x3 - x4 + altSeries [x5] 
          = x1 - x2 + x3 - x4 + x5 

所以全面实施:

altSeries :: Num n => [n] -> n 
altSeries [] = 0 
altSeries [x] = x 
altSeries (x1:x2:t) = x1 - x2 + altSeries t 
+1

可以简化为'altSeries xs = sum(zipWith(*)(cycle [1,-1])xs)'或'altSeries = sum。 zipWith id(循环[id,negate])'。 – melpomene

+0

复杂程度不错的anser。不需要比这更复杂或抽象。 :) – LudvigH

+0

@melpomene:虽然这显然有效,但它引入了很多更高级别的功能和其他魔法。基于这个问题,我认为这不会提高OP的水平。但随时添加一个答案:)我会upvote它。 –

4

你想要的是一个列表,最终看起来像th是[1,-2,3,-4],你可以总结。

您可以制作一个交替符号列表[1,-1]。这可以使用cycle函数无限制。let alternatingSigns = cycle [1,-1]

要变换的[1,2,3,4]列表,你可以压缩无限交替清单与您的清单这样zipWith (*) alternatingSigns input

的整体功能将是这个样子:

altSeries :: Num a => [a] -> a 
altSeries input = let alternatingSigns = cycle [1,-1] 
        in sum $ zipWith (*) alternatingSigns input 
+0

虽然我们在这样做,为什么不消除乘法? altSum = id id。 (右)(+ n))(左(减n))e)(左0)'。 :) – Alec

+0

@Alec'foldr( - )0'似乎更简单(如果你不想严格)。 –

+0

@DavidFletcher我只是在玩耍 - 我的评论并不打算认真。虽然是的,但用foldl''可能会更好。 – Alec