web-dev-qa-db-fra.com

Qu'est-ce qu'un lambda et pourquoi serait-il utile?

Jusqu'à présent, j'ai entendu parler de:

  • Calcul lambda
  • Programmation lambda
  • Expressions lambda
  • Fonctions lambda

Ce qui semble être lié à la programmation fonctionnelle ...

Apparemment, il sera intégré à C++ 1x, donc je pourrais mieux le comprendre maintenant:

http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

Quelqu'un peut-il définir brièvement ce que sont les choses lambdas et indiquer où elles peuvent être utiles?

55
jokoon
  • Calcul lambda

Le lambda calcul est un modèle de calcul inventé par Alonzo Church dans les années 30. La syntaxe et la sémantique de la plupart des langages de programmation fonctionnels s'inspirent directement ou indirectement du calcul lambda.

Le lambda calcul dans sa forme la plus élémentaire a deux opérations: l'abstraction (création d'une fonction (anonyme)) et l'application (appliquer une fonction). L'abstraction est effectuée à l'aide de l'opérateur λ, donnant son nom au calcul lambda.

  • Expressions lambda
  • Fonctions lambda

Les fonctions anonymes sont souvent appelées "lambdas", "fonctions lambda" ou "expressions lambda" car, comme je l'ai dit ci-dessus, λ était le symbole pour créer des fonctions anonymes dans le calcul lambda (et le mot lambda est utilisé pour créer des fonctions anonymes dans de nombreux langages basés sur LISP pour la même raison).

  • Programmation lambda

Ce n'est pas un terme couramment utilisé, mais je suppose que cela signifie la programmation à l'aide de fonctions anonymes ou la programmation à l'aide de fonctions d'ordre supérieur.


Un peu plus d'informations sur les lambdas en C++ 0x, leur motivation et leur relation avec les pointeurs de fonction (une grande partie de cela est probablement une répétition de ce que vous savez déjà, mais j'espère que cela aidera à expliquer la motivation des lambdas et comment ils diffèrent des pointeurs de fonction):

Les pointeurs de fonction, qui existaient déjà en C, sont très utiles pour par exemple passer une fonction de comparaison à une fonction de tri. Cependant, il y a des limites à leur utilité:

Par exemple, si vous souhaitez trier un vecteur de vecteurs par l'élément ith de chaque vecteur (où i est un paramètre d'exécution), vous ne pouvez pas résoudre ce problème avec un pointeur de fonction. Une fonction qui compare deux vecteurs par leur ième élément, devrait prendre trois arguments (i et les deux vecteurs), mais la fonction de tri aurait besoin d'une fonction prenant deux arguments. Ce dont nous aurions besoin est un moyen de fournir en quelque sorte l'argument i à la fonction avant de le passer à la fonction de tri, mais nous ne pouvons pas le faire avec des fonctions C simples.

Pour résoudre ce problème, C++ a introduit le concept des "objets de fonction" ou "foncteurs". Un foncteur est fondamentalement un objet qui a une méthode operator(). Nous pouvons maintenant définir une classe CompareByIthElement, qui prend l'argument i comme argument constructeur et prend ensuite les deux vecteurs à comparer comme arguments à la méthode operator(). Pour trier un vecteur de vecteurs par l'élément ith, nous pouvons maintenant créer un objet CompareByIthElement avec i comme argument, puis passer cet objet à la fonction de tri.

Étant donné que les objets fonction ne sont que des objets et non techniquement des fonctions (même s'ils sont censés se comporter comme eux), vous ne pouvez pas faire pointer un pointeur de fonction vers un objet fonction (vous pouvez bien sûr avoir un pointeur vers un objet fonction, mais il aurait un type comme CompareByIthElement* et ne serait donc pas un pointeur de fonction).

La plupart des fonctions de la bibliothèque standard C++ qui prennent des fonctions comme arguments sont définies à l'aide de modèles afin qu'elles fonctionnent avec les pointeurs de fonction ainsi qu'avec les objets de fonction.

Passons maintenant aux lambdas:

Définir une classe entière à comparer par l'élément ith est un peu prolixe si vous ne l'utilisez qu'une seule fois pour trier un vecteur. Même dans le cas où vous n'avez besoin que d'un pointeur de fonction, la définition d'une fonction nommée n'est pas optimale si elle n'est utilisée qu'une seule fois car a) elle pollue l'espace de nom et b) la fonction va généralement être très petite et il n'y en a pas vraiment une bonne raison d'abstraire la logique dans sa propre fonction (à part cela, vous ne pouvez pas avoir de pointeurs de fonction sans définir une fonction).

Donc, pour corriger ce lambdas ont été introduits. Les lambdas sont des objets de fonction, pas des pointeurs de fonction. Si vous utilisez un littéral lambda comme [x1, x2](y1,y2){bla} un code est généré qui fait essentiellement ce qui suit:

  1. Définissez une classe qui a deux variables membres (x1 Et x2) Et une operator() avec les arguments (y1 Et y2) et le corps bla.
  2. Créez une instance de la classe, en définissant les variables membres x1 Et x2 Sur les valeurs des variables x1 Et x2 Actuellement dans la portée.

Les lambdas se comportent donc comme des objets fonction, sauf que vous ne pouvez pas accéder à la classe générée pour implémenter un lambda autrement qu'en utilisant le lambda. Par conséquent, toute fonction qui accepte des foncteurs comme arguments (signifiant essentiellement toute fonction non-C dans la bibliothèque standard), acceptera les lambdas, mais toute fonction n'acceptant que les pointeurs de fonction ne le sera pas.

43
sepp2k

Fondamentalement, les fonctions lambda sont des fonctions que vous créez "à la volée". En C++ 1x, ils pourraient être utilisés pour améliorer son support pour la programmation fonctionnelle:

std::for_each( begin, end, [](int i){std::cout << i << '\n';} );

Cela se traduira à peu près par un code similaire à celui-ci:

struct some_functor {
  void operator()(int i) {std::cout << i << '\n';}
};

std::for_each( begin, end, some_functor() );

Si vous avez besoin de some_functor Juste pour cet appel à std::for_each(), alors cette fonction lambda a plusieurs avantages:

  • ce qui est fait dans la boucle est spécifié là où la fonction de bouclage est appelée
  • cela vous soulage d'écrire une partie du code de la plaque de la chaudière
  • il n'y a pas de foncteur qui traîne dans une étendue d'espace de noms qui fait que tout le monde regarde le code se demandant à quoi il sert
18
sbi

Une fonction lambda est un autre nom pour une fonction anonyme - essentiellement une fonction sans nom.

Habituellement, vous l'utilisez dans des langues où vous n'aurez besoin d'utiliser la fonction qu'une seule fois. Par exemple au lieu de

def add(a, b)
  return a+b

puis en passant cette fonction dans une autre fonction comme ça

reduce(add, [5,3,2])

Avec un lambda, vous feriez simplement

reduce(lambda x, y: a+b, [5,3,2])
7
Martin Konecny