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
然后
是<