Python 为什么用lambda修复堆栈包装函数会溢出?
如果表达式的计算结果是一个参数的函数,我会认为lambda x:(表达式)(x)与表达式相同,但事实并非如此。考虑Y组合器的两个以下定义:Python 为什么用lambda修复堆栈包装函数会溢出?,python,lambda,functional-programming,stack-overflow,y-combinator,Python,Lambda,Functional Programming,Stack Overflow,Y Combinator,如果表达式的计算结果是一个参数的函数,我会认为lambda x:(表达式)(x)与表达式相同,但事实并非如此。考虑Y组合器的两个以下定义: def Y1(F): left = lambda x: x(x) right = lambda x: F(x(x)) return left(right) def Y2(F): left = lambda x: x(x) right = lambda x: lambda y: (F(x(x)))(y) ret
def Y1(F):
left = lambda x: x(x)
right = lambda x: F(x(x))
return left(right)
def Y2(F):
left = lambda x: x(x)
right = lambda x: lambda y: (F(x(x)))(y)
return left(right)
Y2实际上按预期工作,但调用Y1会引发堆栈溢出。为什么在行为上会有这种差异?不,lambda x:(表达式)(x)
与表达式
不同
它是一个调用时将返回expression
结果的函数,与立即返回结果的expression
不同
结果如何?它是一个参数的函数。但现在还没有。它需要构造、计算。这就是expression
所做的。它计算表示“下一个”递归调用的递归函数,该递归调用可能需要由Ycombinator构造的递归函数完成
Y1
试图过早、过早、急切地找到right
的值——它在返回计算出的递归函数之前尝试这样做。因此永远不会返回,因为Y1
总是在返回前一个递归函数之前尝试计算下一个递归函数,以便调用它
但是Y2
构造递归函数,在需要时计算下一个递归函数;但不是现在,不是“现在”。它将其构造为lambda函数,从而延迟实际计算。lambda函数的构造是一个简单的一步过程,它很快完成,然后返回计算出的递归函数,因此可以使用它——并且只有当它确定需要执行下一级递归调用时,它将在该时间点调用lambda,以在该时间点构造下一个递归函数,即在调用之前
不像
Y1
所尝试的那样提前了很多。函数通过使用参数对表达式进行泛化来从表达式中提取。只有在提供参数时才对此类表达式求值,也就是说,它是惰性求值的。添加一个冗余lambda函数正是这种效果。这种技术被称为,并在经过严格评估的语言中使用,以引入懒散。