Haskell递归'sum'函数

时间:2016-09-12 14:21:35

标签: list function haskell recursion

我发现很难理解以下递归函数的机制:

sums (x:y:ys) = x:sums(x + y : ys)
sums xs = xs

sums ([0..4])

Output:
[0, 1, 3, 6, 10]

这一行究竟发生了什么?:

x:sums(x + y : ys)

我想说在程序可以将'x'附加到列表之前,必须首先执行函数sum(x + y:ys)。但在这种情况下,'x'只会在递归循环结束时附加到列表中一次 - 这不会导致给定的输出......那么我逻辑中的缺陷在哪里?

我的后续问题:我应该如何以合乎逻辑的方式看待/处理递归函数,这会(希望)将我引向'aha-erlebnis'?

非常感谢任何帮助!

4 个答案:

答案 0 :(得分:9)

您可以通过逐步减少来理解Haskell代码。也许以下示例缩减序列可以帮助您实现这一目标。

(一个Haskell实现实际上做了一些与这种减少步骤相关的事情,但可能是以不同的顺序。但是你得到了相同的最终结果。)

在此示例中,您从:

开始
sums [0..4]

稍微扩展[0..4]符号:

sums (0 : 1 : [2..4])

现在我们看到sums的第一个等式与x = 0y = 1ys = [2..4]匹配。所以我们得到:

0 : sums (0 + 1 : [2..4])

我们可以计算0 + 1

0 : sums (1 : [2..4])

稍稍展开[2..4]

0 : sums (1 : 2 : [3..4])

现在我们看到sums的第一个等式再次匹配,这次是x = 1y = 2ys = [3..4]。所以我们得到:

0 : 1 : sums (1 + 2 : [3..4])

我们可以计算1 + 2

0 : 1 : sums (3 : [3..4])

稍稍展开[3..4]

0 : 1 : sums (3 : 3 : [4..4])

现在我们看到sums的第一个等式再次匹配,这次是x = 3y = 3ys = [4..4]。所以我们得到:

0 : 1 : 3 : sums (3 + 3 : [4..4])

我们可以计算3 + 3

0 : 1 : 3 : sums (6 : [4..4])

展开[4..4]

0 : 1 : 3 : sums (6 : 4 : [])

现在我们看到sums的第一个等式再次匹配,这次是x = 6y = 4ys = []。所以我们得到:

0 : 1 : 3 : 6 : sums (6 + 4 : [])

我们可以计算6 + 4

0 : 1 : 3 : 6 : sums (10 : [])

这一次,sums的第一个等式不匹配。但第二个等式匹配。所以我们得到:

0 : 1 : 3 : 6 : 10 : []

这是观察到的输出[0, 1, 3, 6, 10]

答案 1 :(得分:3)

这与任何其他语言中的递归没有什么不同。首次调用_.chunk(不需要括号)时,sums [0..4]x==0y==1。因此,返回值是从ys == [2..4]0创建的新列表。

在严格的语言中,递归调用将在最终创建新列表之前完成。由于Haskell是惰性的,因此返回一个以0开头并继续使用 promise 来评估sums [1..4]的列表。在实际尝试访问列表尾部之前,实际上不会评估递归调用。

答案 2 :(得分:1)

您可能会注意到

sums (x:y:ys) =  x:sums(x + y : ys)

相当于

sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)

和(超过2项)也相当于

sums (x:y:z: w: ys) = x:x+y:x+y+z:sums(x+y+z +w: ys)
sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)

所以通过归纳你有那个

sums(1:2:3:4 :[])

等于

1 : 1 + 2 : 1 + 2 + 3 : 1 + 2 + 3 + 4 : [] 

基于以上内容,您还可以使用

预测
fact(x:y:ys) = x: fact(x * y : ys)
fact(xs) = xs

然后

fact([1..4])

1:1*2:1*2*3:1*2*3*4:[]

答案 3 :(得分:0)

有两个方程定义函数sums。使用匹配参数的第一个等式或其他合适的等式(如1 + 2 = 3)继续重写涉及sums的表达式。

sums [0..4] = 
    -- by syntactic sugar
sums (0:1:2:3:4:[]) = 
    -- by eq. 1, x=0,y=1,ys=2:3:4:[]
0 : sums ((0+1) : 2 : 3:4:[]) = 
    -- by addition 
0 : sums (1 : 2 : 3:4:[]) = 
    -- by eq. 1, x=1, y=2, ys=3:4:[]
0 : 1 : sums ((1+2) : 3 : 4:[]) =
    -- by addition 
0 : 1 : sums (3 : 3 : 4:[]) =
    -- by eq. 1, x=3, y=3, ys=4:[]
0 : 1 : 3 : sums ((3+3) : 4 : []) = 
    -- by addition
0 : 1 : 3 : sums (6 : 4 : []) = 
    -- by eq. 1, x=6, y=4, ys=[]
0 : 1 : 3 : 6 : sums ((6+4):[]) = 
    -- by addition
0 : 1 : 3 : 6 : sums (10:[]) = 
    -- by eq  2,xs=(10:[]) 
0 : 1 : 3 : 6 : 10 : [] = 
    -- by syntactic sugar
[0,1,3,6,10]