lambda函数可以在Python中递归调用自身吗?

时间:2009-01-26 22:42:42

标签: python recursion lambda y-combinator

常规函数可以在其定义中包含对自身的调用,没问题。我无法弄清楚如何使用lambda函数来做这件事,原因很简单,因为lambda函数没有可以引用的名称。有办法吗?怎么样?

14 个答案:

答案 0 :(得分:66)

我能想到的唯一方法就是给这个函数起一个名字:

fact = lambda x: 1 if x == 0 else x * fact(x-1)

或者,对于早期版本的python:

fact = lambda x: x == 0 and 1 or x * fact(x-1)

更新:使用其他答案中的想法,我能够将阶乘函数楔入一个未命名的lambda:

>>> map(lambda n: (lambda f, *a: f(f, *a))(lambda rec, n: 1 if n == 0 else n*rec(rec, n-1), n), range(10))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

所以这是可能的,但不是真的推荐!

答案 1 :(得分:45)

没有reduce,map,名为lambdas或python内部:

(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)

答案 2 :(得分:23)

你不能直接这样做,因为它没有名字。但是使用像Le-Lein指向的Y-combinator这样的辅助函数,你可以通过将函数作为参数传递给自己来创建递归(听起来很奇怪):

# helper function
def recursive(f, *p, **kw):
   return f(f, *p, **kw)

def fib(n):
   # The rec parameter will be the lambda function itself
   return recursive((lambda rec, n: rec(rec, n-1) + rec(rec, n-2) if n>1 else 1), n)

# using map since we already started to do black functional programming magic
print map(fib, range(10))

这将打印前十个Fibonacci数字:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

答案 3 :(得分:23)

与某些人说的相反,你可以直接这样做。

(lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))(n)

第一部分是fixed-point combinator Y ,它有助于lambda演算中的递归

Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))

第二部分是递归定义的因子函数 fact

fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))

Y 应用于 fact 以形成另一个lambda表达式

F = Y(fact)

应用于第三部分, n ,它被视为第n个阶乘

>>> n = 5
>>> F(n)
120

或等效

>>> (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))(5)
120

如果您更喜欢 fibs 事实,您也可以使用相同的组合器

>>> (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: f(i - 1) + f(i - 2) if i > 1 else 1))(5)
8

答案 4 :(得分:11)

是。我有两种方法可以做到,其中一种已经被覆盖了。这是我的首选方式。

(lambda v: (lambda n: n * __import__('types').FunctionType(
        __import__('inspect').stack()[0][0].f_code, 
        dict(__import__=__import__, dict=dict)
    )(n - 1) if n > 1 else 1)(v))(5)

答案 5 :(得分:6)

我从未使用过Python,但this可能就是你想要的。

答案 6 :(得分:2)

这个答案非常基本。这比Hugo Walter的回答简单得多:

>>> (lambda f: f(f))(lambda f, i=0: (i < 10)and f(f, i + 1)or i)
10
>>>
雨果沃尔特回答:

(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)

答案 7 :(得分:1)

def recursive(def_fun):
    def wrapper(*p, **kw):
        fi = lambda *p, **kw: def_fun(fi, *p, **kw)
        return def_fun(fi, *p, **kw)

    return wrapper


factorial = recursive(lambda f, n: 1 if n < 2 else n * f(n - 1))
print(factorial(10))

fibonaci = recursive(lambda f, n: f(n - 1) + f(n - 2) if n > 1 else 1)
print(fibonaci(10))

希望对某人有所帮助。

答案 8 :(得分:0)

嗯,不完全是纯粹的lambda递归,但它适用于只能使用lambdas的地方,例如:减少,映射和列出理解,或其他lambdas。诀窍是从列表理解和Python的名称范围中受益。以下示例按给定的键链遍历字典。

>>> data = {'John': {'age': 33}, 'Kate': {'age': 32}}
>>> [fn(data, ['John', 'age']) for fn in [lambda d, keys: None if d is None or type(d) is not dict or len(keys) < 1 or keys[0] not in d else (d[keys[0]] if len(keys) == 1 else fn(d[keys[0]], keys[1:]))]][0]
33

lambda重用其在列表推导表达式(fn)中定义的名称。这个例子相当复杂,但它显示了这个概念。

答案 9 :(得分:0)

为此,我们可以使用Fixed-point combinators,特别是Z组合器,因为它可以使用严格的语言,也称为急切语言:

const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)))

定义fact函数并对其进行修改:

1. const fact n = n === 0 ? 1 : n * fact(n - 1)
2. const fact = n => n === 0 ? 1 : n * fact(n - 1)
3. const _fact = (fact => n => n === 0 ? 1 : n * fact(n - 1))

请注意:

  

事实=== Z(_fact)

并使用它:

&#13;
&#13;
const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)));

const _fact = f => n => n === 0 ? 1 : n * f(n - 1);
const fact = Z(_fact);

console.log(fact(5)); //120
&#13;
&#13;
&#13;

另见: Fixed-point combinators in JavaScript: Memoizing recursive functions

答案 10 :(得分:0)

Lambda可以轻松替换Python中的递归函数:

例如,这个基本的compound_interest:

def interest(amount, rate, period):
    if period == 0: 
        return amount
    else:
        return interest(amount * rate, rate, period - 1)

可以替换为:

lambda_interest = lambda a,r,p: a if p == 0 else lambda_interest(a * r, r, p - 1)

或更多可见度:

lambda_interest = lambda amount, rate, period: \
amount if period == 0 else \
lambda_interest(amount * rate, rate, period - 1)

用法:

print(interest(10000, 1.1, 3))
print(lambda_interest(10000, 1.1, 3))

输出:

13310.0
13310.0

答案 11 :(得分:0)

顺便说一句,而不是缓慢地计算斐波那契:

f = lambda x: 1 if x in (1,2) else f(x-1)+f(x-2)

我建议快速计算斐波那契:

fib = lambda n, pp=1, pn=1, c=1: pp if c > n else fib(n, pn, pn+pp, c+1)

运行速度非常快。

这也是阶乘计算:

fact = lambda n, p=1, c=1: p if c > n else fact(n, p*c, c+1)

答案 12 :(得分:0)

我知道这是一个旧线程,但它在一些谷歌搜索结果中排名很高:)。随着python 3.8的到来,您可以使用海象运算符以更少的语法实现Y-combinator!

fib = (lambda f: (rec := lambda args: f(rec, args)))\
      (lambda f, n: n if n <= 1 else f(n-2) + f(n-1))

答案 13 :(得分:-3)

如果你是真正的受虐狂,你或许可以使用C扩展来做,但是为了回应Greg(嗨Greg!),这超出了lambda(未命名,匿名)功能的能力。

没有。 (对于大多数的no值)。