问题是在python(或类似的)中给出了一个递归函数,是否可以重写它以便它不引用自身。我做了一个适用于该问题的简单示例。当然,不允许将其设为非递归函数。它仍然必须执行相同的递归过程。
def fact(n):
if n == 0:
return 1
return n * fact(n - 1)
Run Code Online (Sandbox Code Playgroud)
它也相当于简写。
fact = lambda n: 1 if n == 0 else n * fact(n - 1)
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我不应该fact在函数定义内部调用。
编辑:
附加约束:分配不一定是解决方案工作所必需的。
没有附加约束的一种解决方案(来自评论)是创建两个函数a,b它们交替调用并有效地执行阶乘。这是不允许的,因为它要求您在两个变量中分配两个函数。
一个不需要赋值的函数的简单例子是
f = lambda x: x + 1
Run Code Online (Sandbox Code Playgroud)
为了让它在 arugment 上执行55,我可以只写
(lambda x: x + 1)(55)
Run Code Online (Sandbox Code Playgroud)
所以分配是没有必要的。
这有什么提示吗?还是我被一个不可能的问题欺骗了?
您可以使用lambda 演算之类的东西来避免赋值和自引用,用对匿名函数的参数的访问来代替两者。例如:
fact = (lambda f: f(f))(lambda f: (lambda n: n*f(f)(n-1) if n else 1))
Run Code Online (Sandbox Code Playgroud)
在Ideone 中测试。
以下是一些详细信息以了解更多背景信息。
我知道 lambda 演算以其强大(图灵完备)但简约的“编程语言”而闻名。它只使用变量的标识符,可以是绑定的(几乎是函数参数)或未绑定的(在谈论表达式的部分时最相关)。所以感觉这是一个很好的起点。
在 lambda 演算中表达递归的规范方法是使用定点组合器。虽然该组合器可以用 Python 语法天真地表达,但急切求值会导致无限递归。
注释中提到的https://rosettacode.org/wiki/Y_combinator#Python 上的代码通过将递归调用之一延迟到函数实际被调用来避免这种无限递归。但我更愿意将这种方法的详细解释留给单独的答案。
在 lambda 演算中表达递归的核心思想是什么?将函数作为参数传递给自身。所以我从这个开始:
lambda f: f(f) # ? f.f f
Run Code Online (Sandbox Code Playgroud)
我需要将该函数传递给另一个将函数作为值的函数。喜欢lambda f: …。并且该调用的结果应该是一个函数,该函数应该将 ann作为参数来计算阶乘。我的第一个近似是将f自身视为递归调用的表达式,所以我首先想到的是:
(lambda f: f(f))(lambda f: (lambda n: n*f(n-1) if n else 1))
Run Code Online (Sandbox Code Playgroud)
但后来我意识到这是错误的:f它本身不是递归调用,因为f它是带有参数的函数f。f(f)递归调用也是如此,导致我在开始时打印的解决方案。