我在评估延迟的工作方式上遇到了一些问题。我试图用Y-Combinator来理解它:
如果我们编写一个简单版本的Y-Combinator,我们就会遇到无限递归的问题:
Ysimple = (lambda f : (lambda x : f(x(x))) (lambda x : f(x(x))))
当我们构建递归函数时,会出现问题:
almost_factorial = lambda f : lambda n : 1 if n == 0 else n * f(n-1)
factorial = Ysimp(almost_factorial) # <- infinite recursion
Ysimple =(lambda f :( lambda x:f(x(x)))(lambda x:f(x(x))))
[上一行重复995次] RecursionError:最大值 超出递归深度
但我们可以在延迟抽象中包装第二个或两个f(x(x))
- 表达式:
Ydelay = (lambda f : (lambda x : f(x(x))) (lambda x : f(lambda y: x(x)(y))) )
现在代码工作得很好。但为什么呢?
如果我们的文件中只有Ysimple
,则不会评估任何内容。所以我假设只评估作为顶级表达式的lambdas。
我做了一些手动评估步骤,但我没有看到他们发生延迟的原因:
Ysimple F = (lambda f : (lambda x : f(x(x))) (lambda x : f(lambda y: x(x)(y)))) F
-> (lambda x : F(x(x))) (lambda x : F(lambda y: x(x)(y)))
-> F( (lambda x : F(lambda y: x(x)(y))) (lambda x : F(lambda y: x(x)(y))) )
Ydelay F = (lambda f : (lambda x : f(x(x))) (lambda x : f(x(x)))) F
-> (lambda x : F(x(x))) (lambda x : F(x(x)))
-> F( (lambda x : F(x(x))) (lambda x : F(x(x))) )
延迟发生在哪里?在这两种情况下,F
都是顶级表达式,在这两种情况下,lambda x
的级别都低于F
。延迟lambda y
起什么作用?
同样,为什么延迟在第一行如何工作:
(lambda x : x(x)) (lambda y: lambda x : x(x)(y))
(lambda x : x(x)) (lambda x: x(x))
答案 0 :(得分:0)
当我们将lambda表达式转换为普通函数语法时,整个事情变得更加明显:
def f(x): # lambda x : x(x)
return x(x)
def g(y): # lambda y: lambda x : x(x)(y)
def fg(x):
return (x(x))(y)
return fg
f(g) # does not recurse infinitely
当我们手动评估与(lambda x : x(x)) (lambda y: (lambda x : x(x))(y))
对应的表达式时,我们得到
f(g) = g(g) = lambda x : x(x)(g)
在评估与(lambda x : x(x)) (lambda y: y(y))
产量相对应的产量时
f(f) = f(f) = f(f) = ...
我们现在可以看到为什么抽象会停止递归。