Une fonction régulière peut contenir un appel à elle-même dans sa définition, pas de problème. Je n'arrive pas à comprendre comment le faire avec une fonction lambda bien que pour la simple raison que la fonction lambda n'a pas de nom auquel se référer. Y a-t-il un moyen de le faire? Comment?
La seule façon pour moi d’y parvenir consiste à donner un nom à la fonction:
fact = lambda x: 1 if x == 0 else x * fact(x-1)
ou alternativement, pour les versions antérieures de python:
fact = lambda x: x == 0 and 1 or x * fact(x-1)
Mise à jour : en utilisant les idées des autres réponses, j'ai été en mesure de caler la fonction factorielle en un seul lambda sans nom:
>>> 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]
C'est donc possible, mais pas vraiment recommandé!
sans réduire, mapper, nommer internes lambdas ou python:
(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
Vous ne pouvez pas le faire directement, car il n’a pas de nom. Mais avec une fonction d'assistance telle que celle indiquée par Y-combinator, citée par Lemmy, vous pouvez créer une récursivité en lui passant la fonction comme paramètre (aussi étrange que cela puisse paraître):
# 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))
Ceci affiche les dix premiers nombres de Fibonacci: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
,
Contrairement à ce que sth a dit, vous POUVEZ le faire directement.
(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)
La première partie est le combinateur à point fixeY qui facilite la récursivité dans le calcul lambda
Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))
la deuxième partie est la fonction factorielle fait définie récursivement
fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))
Y est appliqué à fact pour former une autre expression lambda
F = Y(fact)
qui est appliqué à la troisième partie, n, qui évoque à la nième factorielle
>>> n = 5
>>> F(n)
120
ou équivalent
>>> (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
Si toutefois vous préférez fibs à facts, vous pouvez le faire aussi en utilisant le même combinateur
>>> (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
Oui. J'ai deux façons de le faire, et une était déjà couverte. C'est ma manière préférée.
(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)
Je n'ai jamais utilisé Python, mais this est probablement ce que vous recherchez.
Cette réponse est assez basique. C'est un peu plus simple que la réponse de Hugo Walter:
>>> (lambda f: f(f))(lambda f, i=0: (i < 10)and f(f, i + 1)or i)
10
>>>
Réponse de Hugo Walter:
(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
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))
J'espère que cela serait utile à quelqu'un.
Eh bien, pas exactement la récursion lambda pure, mais elle est applicable dans les endroits où vous ne pouvez utiliser que des lambdas, par exemple. réduire, mapper et lister les compréhensions, ou autres lambdas. L'astuce consiste à tirer profit de la compréhension des listes et de la portée du nom de Python. L'exemple suivant parcourt le dictionnaire par la chaîne de clés donnée.
>>> 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
Le lambda reprend son nom défini dans l'expression de compréhension de liste (fn). L'exemple est plutôt compliqué, mais il montre le concept.
Pour cela, nous pouvons utiliser Des combinateurs à point fixe , en particulier un combinateur Z
, car il fonctionnera dans des langages stricts, également appelés langages désirés:
const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)))
Définissez la fonction fact
et modifiez-la:
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))
Remarquerez que:
fait === Z (_fact)
Et utilisez-le:
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
Voir aussi: Combinateurs à points fixes en JavaScript: Mémorisation des fonctions récursives
Lambda peut facilement remplacer des fonctions récursives en Python:
Par exemple, ce compound_interest basique:
def interest(amount, rate, period):
if period == 0:
return amount
else:
return interest(amount * rate, rate, period - 1)
peut être remplacé par:
lambda_interest = lambda a,r,p: a if p == 0 else lambda_interest(a * r, r, p - 1)
ou pour plus de visibilité:
lambda_interest = lambda amount, rate, period: \
amount if period == 0 else \
lambda_interest(amount * rate, rate, period - 1)
USAGE:
print(interest(10000, 1.1, 3))
print(lambda_interest(10000, 1.1, 3))
Sortie:
13310.0
13310.0