List 哈斯克尔递归';总和';作用

List 哈斯克尔递归';总和';作用,list,function,haskell,recursion,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'只会附加到列表中一次-在递归循环的末尾-这不会导致给定的输出。。。那么,我的逻辑缺陷在哪里呢 我的后续问题:我应该如何

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

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”


非常感谢您的帮助

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


在严格的语言中,递归调用将在最终创建新列表之前完成。由于Haskell是懒惰的,因此返回一个以0开头并以承诺计算
和[1..4]
的列表。在有人真正尝试访问列表的尾部之前,递归调用实际上不会被计算。

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


在严格的语言中,递归调用将在最终创建新列表之前完成。由于Haskell是懒惰的,因此返回一个以0开头并以承诺计算
和[1..4]
的列表。只有当有人真正尝试访问列表的尾部时,才会对递归调用进行实际计算。

您可以通过逐步缩减来理解Haskell代码。也许下面的示例还原序列有助于您的aha

(Haskell实现实际上做了一些与这些缩减步骤相关的事情,但顺序可能不同,但最终结果是一样的)

在本例中,您从以下内容开始:

sums [0..4]
[0..4]
符号稍微展开一点:

sums (0 : 1 : [2..4])
现在我们看到,
和的第一个等式
匹配,其中
x=0
y=1
,和
ys=[2..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
0+1

0 : sums (1 : [2..4])
并稍微展开
[2..4]

0 : sums (1 : 2 : [3..4])
0 : 1 : sums (3 : 3 : [4..4])
现在我们看到
和的第一个方程再次匹配,这次是
x=1
y=2
,和
ys=[3..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
1+2

0 : 1 : sums (3 : [3..4])
并稍微展开
[3..4]

0 : sums (1 : 2 : [3..4])
0 : 1 : sums (3 : 3 : [4..4])
现在我们看到
和的第一个方程再次匹配,这次是
x=3
y=3
,和
ys=[4..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
3+3

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

0 : 1 : 3 : sums (6 : 4 : [])
现在我们看到
和的第一个方程再次匹配,这次是
x=6
y=4
,和
ys=[]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
6+4

0 : 1 : 3 : 6 : sums (10 : [])
这一次,
和的第一个等式不匹配。但第二个等式是匹配的。因此,我们得到:

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

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

您可以通过逐步简化来理解Haskell代码。也许下面的示例还原序列有助于您的aha

(Haskell实现实际上做了一些与这些缩减步骤相关的事情,但顺序可能不同,但最终结果是一样的)

在本例中,您从以下内容开始:

sums [0..4]
[0..4]
符号稍微展开一点:

sums (0 : 1 : [2..4])
现在我们看到,
和的第一个等式
匹配,其中
x=0
y=1
,和
ys=[2..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
0+1

0 : sums (1 : [2..4])
并稍微展开
[2..4]

0 : sums (1 : 2 : [3..4])
0 : 1 : sums (3 : 3 : [4..4])
现在我们看到
和的第一个方程再次匹配,这次是
x=1
y=2
,和
ys=[3..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
1+2

0 : 1 : sums (3 : [3..4])
并稍微展开
[3..4]

0 : sums (1 : 2 : [3..4])
0 : 1 : sums (3 : 3 : [4..4])
现在我们看到
和的第一个方程再次匹配,这次是
x=3
y=3
,和
ys=[4..4]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
3+3

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

0 : 1 : 3 : sums (6 : 4 : [])
现在我们看到
和的第一个方程再次匹配,这次是
x=6
y=4
,和
ys=[]
。因此,我们得到:

0 : sums (0 + 1 : [2..4])
0 : 1 : sums (1 + 2 : [3..4])
0 : 1 : 3 : sums (3 + 3 : [4..4])
0 : 1 : 3 : 6 : sums (6 + 4 : [])
0 : 1 : 3 : 6 : 10 : []
我们可以计算
6+4

0 : 1 : 3 : 6 : sums (10 : [])
这一次,
和的第一个等式不匹配。但第二个等式是匹配的。因此,我们得到:

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

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

有两个方程定义函数
和。使用与参数匹配的第一个方程或其他合适的方程(如1+2=3),继续重写包含
求和的表达式


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

你会注意到的

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)
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)
和(超过2项)也相当于

sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)
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
然后

你会注意到的

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)
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)
和(超过2项)也相当于

sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)
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
然后

是<