De quoi parle-t-on sans cesse de «Lambda»?

93

De quoi parle-t-on sans cesse de «Lambda»? Beaucoup de gens semblent l'adorer, mais tout ce que je peux en déduire, c'est que c'est juste une façon de regrouper beaucoup de lignes de code dans une seule expression.

Quelqu'un peut-il s'il vous plaît m'éclairer sur sa vraie valeur?

Josh Hunt
la source
16
Puis - je signaler à answerers que le questionneur ne mentionne nulle part .net
Question craquante. Merci d'avoir posé la question.
Peanut
Les lambdas appartiennent au monde de la programmation fonctionnelle (programmation déclarative).
RBT

Réponses:

179

Fonctions sans nom

En termes simples, un lambda est une fonction sans nom ou une fonction anonyme. Un petit morceau de code exécutable, qui peut être transmis comme s'il s'agissait d'une variable. En JavaScript:

function () {}; // very simple

Voyons maintenant quelques utilisations de ces lambdas.

Résumé du code passe-partout

Les lambdas peuvent être utilisés pour extraire le code standard. Par exemple des boucles. Nous avons l'habitude d'écrire foret de whileboucler toute la journée. Mais c'est du code qui ne s'écrit pas. Nous pourrions extraire le code à l'intérieur de la boucle, la partie la plus importante de la boucle, et faire abstraction du reste:

for (var i=0; i<array.length; i++) {
    // do what something useful with array[i]
}

en utilisant les forEachobjets de tableau, devient:

array.forEach(function (element, index) {
   // do something useful with element
   // element is the equivalent of array[i] from above
});

L'abstraction ci-dessus n'est peut-être pas très utile, mais il existe d'autres fonctions d'ordre supérieur, comme forEach, qui effectuent des tâches beaucoup plus utiles. Par exemple filter:

var numbers = [1, 2, 3, 4];
var even    = [];

// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        even.push(numbers[i]);
    }
}

alert(even);

// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
    return number % 2 === 0;
});

alert(even);

Délai d'exécution du code

Dans certains environnements, dans lesquels le concept d'événement est disponible, nous pourrions utiliser des lambdas pour répondre aux événements qui peuvent se produire à un moment donné.

window.onload = function () {
    alert("Loaded");
};

window.setTimeout(function () {
    alert("Code executed after 2 seconds.");
}, 2000);

Cela aurait pu être fait d'autres manières, mais celles-ci sont plutôt verbeuses. Par exemple, en Java, il y a l' Runnableinterface.

Usines de fonctions

Jusqu'à ce point, nous n'utilisions que des lambdas pour ses capacités de sucre syntaxique principalement. Mais il y a des situations où les lambdas peuvent être beaucoup plus utiles. Par exemple, nous pouvons avoir des fonctions qui renvoient des lambdas. Disons que nous avons une fonction dont nous voulons que ses valeurs de retour soient mises en cache.

var users = [];
var getUser = function (name) {
    if (! users[name]) {
        // expensive operations to get a user. Ajax for example
        users[name] = user_from_ajax;
    }

    return users[name];
};

Plus tard, nous pouvons remarquer que nous avons une fonction similaire:

var photos = [];
var getPhoto = function (name) {
    if (! photo[name]) {
        // expensive operations to get a user. Ajax for example
        photos[name] = photo_from_ajax;
    }

    return photos[name];
};

Il y a clairement un modèle là-dedans, alors abstenons-le. Utilisons la mémorisation .

/**
 * @param {Array}     store Data structure in which we cache lambda's return values
 * @param {Function}  lambda
 * @return {Function} A function that caches the result of calling the lambda param
 */
var memoize = function (store, lambda) {
    // return a new lambda
    return function (name) {
        if (! store[name]) {
            // Execute the lambda and cache the result
            store[name] = lambda(name);
        }

        return store[name];
    };
};

var getUsers = memoize([], function (name) {
    // expensive operations to get a user. Ajax for example
});

var getPhotos = memoize([], function (name) {
    // expensive operations to get a photo. Ajax for example
});

Comme vous pouvez le voir, en utilisant des lambdas, nous avons pu faire abstraction de la logique de mise en cache / mémorisation. Si pour l'autre exemple il y avait des solutions de contournement, je pense que ce problème particulier est difficilement résolu par d'autres techniques. Nous avons réussi à extraire un code passe-partout important en un seul endroit. Sans oublier que nous nous sommes débarrassés des variables globales userset photos.

En regardant votre profil, je vois que vous êtes principalement un utilisateur de Python. Pour le modèle ci-dessus, Python a le concept de décorateurs. Il existe de nombreux exemples sur le net pour les décorateurs de mémorisation . La seule différence est qu'en Python, vous avez très probablement une fonction imbriquée nommée à l' intérieur de cette fonction de décorateur. La raison étant que Python ne prend en charge que les lambdas à expression unique. Mais le concept est le même.

Comme exemple d'utilisation de Python lambda. Le code ci-dessus dans lequel nous avons filtré les nombres pairs peut être représenté en Python comme ceci:

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

Quoi qu'il en soit, les lambdas ne sont pas si puissants sans fermetures. Les fermetures sont ce qui rend le concept de lambdas si puissant. Dans mon exemple de mémorisation, j'ai utilisé des fermetures pour créer une fermeture autour du storeparamètre. De cette façon, j'ai accès à ce paramètre même après que la memoizefonction a renvoyé son résultat (un lambda).

Ionuț G. Stan
la source
3
Wow vous avez mis beaucoup de temps là-dedans.
mk12 du
4
@ Mk12, dans la rédaction de la réponse, pas vraiment. En apprenant ce truc, oui, ça fait un moment que j'ai commencé :)
Ionuț G. Stan
Bonne réponse mais informations manquantes sur les "interfaces fonctionnelles" (du point de vue Java).
djangofan
Quels sont ces opérateurs "===" dans votre "Abstracting code standard"?
Don
@Don voir ce stackoverflow.com/questions/359494/…
Ionuț G. Stan
19

Le terme «lambda» est utilisé pour désigner une fonction anonyme, généralement une fermeture . Ils sont utiles car ils vous permettent d'écrire des fonctions qui utilisent d'autres fonctions sans gonfler inutilement votre code. Par exemple, dans Ruby:

(1..100).select {|num| num % 2 == 0}

Cela créera un tableau contenant les nombres pairs entre 1 et 100. Nous n'avons pas besoin d'écrire une boucle explicite - la méthode select prend une fonction qu'elle utilise pour tester les valeurs, donc tout ce dont nous avons besoin est notre logique personnalisée. Cela nous permet de personnaliser considérablement la méthode sans pratiquement aucun effort ni surcharge. Fondamentalement, nous pouvons composer des fonctions à partir de fonctions plus petites.

Ce n'est qu'un exemple simple de ce qu'ils peuvent faire. La capacité de passer des fonctions en tant que données est vraiment puissante et les programmeurs de langage fonctionnels font régulièrement des choses vraiment étonnantes avec.

Mandrin
la source
6
Vous devriez peut-être ajouter que la chose dans les tuyaux est le paramètre. Je fais partie de ces personnes qui ont du mal à lire ruby.
Skurmedel
C'est une bonne réponse. La seule raison pour laquelle Ionut a obtenu mon vote est qu'il nous a dit pourquoi nous devrions nous soucier (en détail) des lambdas.
Frank Shearar
Je ne suis pas d'accord pour dire que les lambdas sont généralement des fermetures.
jwg
6

"Lambda" peut-être juste trop peu. Jetez un œil au calcul Lambda . C'est utile dans la programmation fonctionnelle.

Et la programmation fonctionnelle est encore un autre paradigme de programmation (comme procédural ou orienté objet).

SALUT
la source
5
Ensuite, les gens parlent de "Lambda", ils parlent probablement de fonction anonyme, de pointeurs de fonction, de fermeture ou de quelque chose de similaire. Ne se réfère presque jamais à la vraie chose de calcul lambda.
J-16 SDiZ
Heureux que vous ayez mentionné le calcul Lambda.! +1.
RBT
5

Les lambdas dans .NET sont souvent appelés «sucre syntaxique». Ils n'affectent pas directement la fonctionnalité, mais ils facilitent l'utilisation de la langue par les gens.

Lorsque vous aurez compris la puissance de leur utilisation, je suis sûr que vous constaterez que vous allez écrire moins de code par rapport à l'ancienne méthode utilisant des délégués / méthodes anonymes.

carré rouge
la source
1
Je ne pense pas que quiconque ait mentionné .NET, donc l'OP est probablement mieux avec une réponse plus générale.
molf
2
c'est pourquoi j'ai clarifié en répondant à propos de .net. Si d'autres pépient avec leur implémentation linguistique, les questions et réponses aideront de nombreuses personnes, quel que soit leur choix de langue.
redsquare
Cette réponse se lit comme si vous aviez entendu quelque chose sur les lambdas, mais vous ne les comprenez pas encore vous-même.
jwg
2

Le Dr Dobbs Journal a un article utile présentant les expressions lambda (dans le contexte du C ++ mais je pense que vous pouvez appliquer les principes à n'importe quel langage).

Comme le dit l'article: "Une expression lambda est une expression très compacte qui ne nécessite pas de définition de classe / fonction distincte."

Donc, en utilisant les exemples des listes 1 et 2 de DDJ au lieu d'écrire:

std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));

Ce qui nécessite une définition de classe distincte comme:

template <typename T, typename Stream> class print_to_stream_t {
  Stream& stream_;
public:
  print_to_stream_t(Stream& s):stream_(s) {}
  void operator()(const T& t) const {
    stream_ << t;
  }
};
template <typename T,typename Stream> 
print_to_stream_t<T,Stream>   print_to_stream(Stream& s) {
  return print_to_stream_t<T,Stream>(s);
}

En utilisant la bibliothèque Lambda Boost, cela peut devenir:

std::for_each(vec.begin(),vec.end(),std::cout << _1);

Ce qui maintient la définition en ligne.

L'article explique également d'autres applications des expressions lambda.

Je pense qu'un point clé de l'article DDJ est "En règle générale, les expressions lambda sont utilisées lorsque des fonctions petites et pas trop complexes sont nécessaires sur le site d'appel. Si la fonction n'était pas triviale, vous ne voudriez pas d'une expression lambda mais d'une fonction normale ou un objet de fonction. "

Danio
la source
2

Si vous avez déjà travaillé avec des fonctions / méthodes qui utilisent des pointeurs de fonction, des délégués, une stratégie ou une gestion des modèles / événements d'observateur et que vous vous êtes dit "J'écris toute cette fonction juste pour l'utiliser une seule fois - pour la transmettre à cette méthode ; J'aimerais pouvoir simplement l'écrire sur place, plutôt que d'encombrer mon code "- c'est là que vous pourriez utiliser les fonctions Lambda. Les langages qui prennent en charge cette construction tirent également largement parti du concept de passage de fonctions en tant que paramètres, en particulier en ce qui concerne le travail avec des listes (fonctions de première classe et fonctions d'ordre supérieur). Cela est particulièrement vrai pour les langages fonctionnels, qui reposent sur la composition de fonctions plutôt que sur la modification de la mémoire pour les calculs. Dans certains cas (dans des langages tels que Python),

TR
la source
2

«lambda» en tant que mot est la terminologie de l'époque où les informaticiens étaient aussi susceptibles d'être formés en mathématiques ou en logique que d'avoir un diplôme en informatique. Certains d'entre eux ont élaboré un paradigme appelé «programmation fonctionnelle», assez différent de l'impératif et assez puissant aussi. Autant que je sache c'est le milieu où le terme est entré en usage.

Les mathématiciens et les logiciens sont habitués à utiliser des mots étranges.

«lambda» semble vraiment ésotérique - comme s'il s'agissait d'une chose très étrange et spéciale. Vraiment, si vous écrivez du JavaScript pour une application de navigateur Web et que vous utilisez l'idiome "var foo = function () {...}", vous avez toujours utilisé les fonctions lambda.

Peter Mortensen
la source
1

Une expression lambda est une forme simple de fonction. L'idée est que quelque chose de la forme à gauche (équivalent aux paramètres) devient quelque chose de la forme à droite (équivalent au corps).

par exemple, en c sharp:

x => x * x

est un lambda pour mettre au carré une valeur. Quelque chose de la forme

x

devient quelque chose de la forme

x * x
Dave Cousineau
la source
0

"Une expression lambda est une fonction anonyme qui peut contenir des expressions et des instructions, et peut être utilisée pour créer des délégués ou des types d'arborescence d'expression.

Toutes les expressions lambda utilisent l'opérateur lambda =>, qui est lu comme "va à". Le côté gauche de l'opérateur lambda spécifie les paramètres d'entrée (le cas échéant) et le côté droit contient l'expression ou le bloc d'instructions. L'expression lambda x => x * x est lue «x va à x fois x».

depuis MSDN

Fermin
la source
4
Ouais, Microsoft fait croire à tout le monde qu'ils l'ont inventé. Les expressions Lambda sont cependant antérieures à Microsoft. C'est un terme mathématique qui a été appliqué à plusieurs langages de programmation. (Ce qui est possible, puisque les mathématiques pourraient être considérées comme un langage informatique en soi.)
Wim ten Brink
4
Notez que cela est spécifique à l'implémentation .Net de Microsoft. Ce n'est pas un énorme écart par rapport à l'idée générale d'un lambda, mais je pense que la fonctionnalité implémentée dans Lisp est plus "standard".
Chuck
2
Cette réponse n'explique pas du tout ce qu'est un Lambda (nécessite des définitions de fonction anonyme, de délégué, de type d'arborescence d'expression) et n'explique certainement pas quelle est sa valeur.
danio le
0

Pour une explication complète des expressions Lambda, consultez également Wikipedia . (Faites défiler jusqu'à la partie Calcul Lambda et langages de programmation .) Les expressions Lambda ne sont pas si nouvelles et elles ne font pas seulement partie de C #, mais quelque chose qui a été introduit dans l'informatique il y a près de 80 ans! Les expressions Lambda sont la base de la programmation fonctionnelle.

Sa valeur? Eh bien, étant donné qu'il est en fait assez ancien, je dirais: très utile pour quiconque fait des calculs.

Wim ten Brink
la source
0

Si vous aimez Java, vous avez beaucoup entendu parler de lambdas ou de fermetures au cours des deux derniers mois, car il y avait différentes propositions pour ajouter cette fonctionnalité à Java 7. Cependant, je pense que le comité l'a abandonnée. L'une des propositions vient de Neal Gafter et est expliquée en détail ici: javac.info . Cela m'a aidé à comprendre les cas d'utilisation et les avantages (en particulier par rapport aux classes internes)

Tim Büthe
la source
0

Vous trouverez tout ce que vous devez savoir (sur C # Lambdas) pour commencer ici:
Expressions Lambda

Robert Koritnik
la source
-1

Oui, c'est juste un moyen de regrouper beaucoup de lignes de code dans une seule expression. Mais étant un bourrage aussi efficace, il permet de nouvelles façons de structurer votre programme.

Souvent, on éviterait d'écrire des délégués ou des rappels et reviendrait au style procédural simplement parce que déclarer de nouvelles fonctions ou classes pour une seule expression représente trop de travail.

Les expressions Lambda valent la peine d'utiliser des rappels, même pour les tâches les plus infimes, ce qui peut rendre le code plus clair. Peut-être pas.

ima
la source