Skip to main content
 首页 » 编程设计

python之在函数式编程(或其他方式)中递归时,使用显式状态变量的好处/限制是什么

2025年05月04日28落叶

我一直在研究 Python 中的函数式编程,并意识到有两种方法可以用递归替换循环。规范递归技术似乎不需要任何状态,例如下面的“factorial_canon”。另一种方法是使用状态变量来存储中间结果,例如下面的“factorial_alter”。

def factorial_canon(value): 
    if value == 1: 
        return 1 
    else: 
        return value*factorial_canon(value-1) 
 
def factorial_alter(value, current = 1, state = 1): 
    if current <= value: 
        return factorial_alter(value, current + 1, state*current) 
    else: 
        return state 
 
print 'factorial_canon: ', factorial_canon(5) 
print 'factorial_alter: ', factorial_alter(5) 

结果:

> factorial_canon: 120 
> factorial_alter: 120 

规范方法适用于小问题,但在实际项目中很快就会变得复杂。替代(基于状态)方法有什么缺点吗?它是否违反了纯函数实现的任何条件,例如,关于可变变量?

我意识到基于状态的方法无法从尾调用优化中获益,但我认为这无关紧要,因为 Python 无论如何都不支持此类优化。

请您参考如下方法:

不,恰恰相反:状态传递范例使 TCO 成为可能;简单递归的“规范”版本不是尾递归,因此 TCO 根本不适用于它。

尾调用优化的本质是堆栈帧变量(即参数)的重用:

    fact 5: 
    fact_state 5 1 1: 
    fact_state 5 2 2: 
    fact_state 5 3 6: 
    fact_state 5 4 24: 
    fact_state 5 5 120: 
    return 120 

简单递归版本必须在递归调用返回后执行乘法,因此必须将当前 n 压入堆栈,以便在递归调用返回时将其乘以返回值。

尾递归版本在递归调用之前相乘,因此返回后不需要做任何事情,不需要压栈,因此可以将最终值返回给系统(只有一个最终返回)。

这意味着递归尾部调用替换当前调用;它的参数存储在函数调用框架中,得到重用——就地更新(由编译器改变);在功能上将整个计算变成一个循环。毕竟,这是 TCO 的目标。

当然在Python中使用递归的方法就是不在Python中使用递归。正如您所说,Python 不提供 TCO。我们的程序仍然在其指令集 IOW 循环中具有程序计数器、跳转和可更新寄存器的计算机上运行。也许当智能尘埃到来时,这会改变。具有 TCO 的递归被转换为循环,这是将 TCO 放在首位的全部原因。

( see also )