75

通常の関数には、その定義にそれ自体への呼び出しを含めることができますが、問題ありません。ラムダ関数には参照する名前がないという単純な理由で、ラムダ関数でそれを行う方法がわかりません。それを行う方法はありますか?どのように?

4

15 に答える 15

80

これを行うために私が考えることができる唯一の方法は、関数に名前を付けることです。

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)

更新:他の回答のアイデアを使用して、階乗関数を単一の名前のないラムダにくさびにすることができました:

>>> 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]

可能ですが、あまりお勧めしません。

于 2009-01-26T23:04:03.290 に答える
60

reduce、map、named lambdas、または python internals なし:

(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
于 2012-01-02T16:34:15.837 に答える
32

sthが言ったことに反して、これを直接行うことができます。

(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)

最初の部分は、ラムダ計算での再帰を容易にする固定小数点コンビネータ Yです。

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

2 番目の部分は、再帰的に定義された階乗関数の事実です。

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

Yがファクトに適用され、別のラムダ式が形成されます

F = Y(fact)

これは 3 番目の部分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

ただし、事実よりもフィブを好む場合は、同じコンビネーターを使用してそれを行うこともできます

>>> (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
于 2012-04-13T16:50:05.533 に答える
23

名前がないため、直接行うことはできません。しかし、Y コンビネーターの Lemmy が指摘したようなヘルパー関数を使用すると、関数をパラメーターとしてそれ自体に渡すことで再帰を作成できます (奇妙に聞こえるかもしれませんが)。

# 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))

これは、最初の 10 個のフィボナッチ数を表示します: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55],

于 2009-01-26T23:16:29.710 に答える
12

はい。2 つの方法がありますが、1 つは既に説明済みです。これは私の好みの方法です。

(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)
于 2009-01-27T02:52:33.393 に答える
0

このために、固定小数点コンビネーター、具体的にはコンビネーターを使用できます。これは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)

そしてそれを使用します:

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

関連項目: JavaScript の固定小数点コンビネータ: 再帰関数のメモ化

于 2018-03-08T18:14:13.280 に答える
-3

あなたが真に自虐的であれば、C 拡張機能を使用してそれを行うことができるかもしれませんが、これはラムダ (無名、無名) 関数の機能を超えています。

いいえ (no のほとんどの値)。

于 2009-01-26T23:17:39.583 に答える