Article de reference

Fonction anonyme

En programmation , une fonction anonyme (ou fonction littérale , fonction lambda ou bloc ) est une définition de fonction non associée à un identifiant . Les fonctions anonymes ...

En programmation , une fonction anonyme (ou fonction littérale , fonction lambda ou bloc ) est une définition de fonction non associée à un identifiant . Les fonctions anonymes sont souvent des arguments passés à des fonctions d'ordre supérieur ou servent à construire le résultat d'une fonction d'ordre supérieur qui doit renvoyer une fonction. Si la fonction n'est utilisée qu'une seule fois, ou un nombre limité de fois, une fonction anonyme peut être syntaxiquement plus légère qu'une fonction nommée. Les fonctions anonymes sont omniprésentes dans les langages de programmation fonctionnelle et dans d'autres langages possédant des fonctions de première classe , où elles remplissent pour le type fonction le même rôle que les littéraux pour les autres types de données .

Les fonctions anonymes trouvent leur origine dans les travaux d' Alonzo Church et son invention du lambda-calcul en 1936, avant l'avènement des ordinateurs. Dans plusieurs langages de programmation, les fonctions anonymes sont introduites par le mot-clé `lambda` , et elles sont souvent appelées lambdas ou abstractions lambda . Présentes dans les langages de programmation depuis Lisp en 1958, les fonctions anonymes sont de plus en plus prises en charge par les langages modernes.

Noms

Les termes « abstraction lambda », « fonction lambda » et « expression lambda » font référence à la notation d'abstraction de fonction dans le lambda-calcul, où la fonction usuelle s'écrirait et où est une expression qui utilise . À comparer avec la syntaxe Python de . lambdax:M

Le nom « fonction fléchée » fait référence au symbole mathématique « mappe vers », . À comparer avec la syntaxe JavaScript de . x=>M

Utilisations

Les fonctions anonymes peuvent encapsuler des fonctionnalités qui ne nécessitent pas de nommage et sont destinées à un usage ponctuel ou localisé. Les fermetures et la curryfication en sont quelques exemples notables .

L'utilisation de fonctions anonymes est une question de style. Ce n'est jamais la seule solution à un problème ; chaque fonction anonyme peut être définie comme une fonction nommée et appelée par son nom. Les fonctions anonymes offrent souvent une notation plus concise que les fonctions nommées. Dans les langages qui n'autorisent pas la définition de fonctions nommées dans une portée locale, les fonctions anonymes peuvent assurer une encapsulation via une portée localisée. Cependant, le code contenu dans le corps d'une telle fonction anonyme peut ne pas être réutilisable ou se prêter à des tests séparés. Les fonctions anonymes courtes et simples utilisées dans des expressions peuvent être plus faciles à lire et à comprendre que les fonctions nommées définies séparément, bien que l'absence d'un nom descriptif puisse nuire à la lisibilité du code.

Dans certains langages de programmation, les fonctions anonymes sont couramment implémentées à des fins très spécifiques, comme la liaison d'événements à des rappels ou l'instanciation de la fonction pour des valeurs particulières, ce qui peut être plus efficace dans un langage de programmation dynamique , plus lisible et moins sujet aux erreurs que l'appel d'une fonction nommée.

Les exemples suivants sont écrits en Python 3.

Tri

De nombreux langages proposent une fonction générique permettant de trier une liste (ou un tableau) d'objets selon un ordre déterminé par une fonction de comparaison. Cette fonction compare deux objets afin de déterminer s'ils sont égaux ou si l'un est supérieur ou inférieur à l'autre. Utiliser une expression de comparaison anonyme passée en argument à une fonction de tri générique est souvent plus concis que de créer une fonction de comparaison nommée.

Considérons ce code Python qui trie une liste de chaînes de caractères par longueur :

a : list [ str ] = [ "house" , "car" , "bike" ] a . sort ( key = lambda x : len ( x )) print ( a ) # affiche ['car', 'bike', 'house']

La fonction anonyme dans cet exemple est l'expression lambda :

lambda x : len ( x )

La fonction anonyme accepte un argument, x, et renvoie la longueur de son argument, qui est ensuite utilisée par la sort()méthode comme critère de tri.

La syntaxe de base d'une fonction lambda en Python est :

lambda arg1 , arg2 , arg3 , ... : < opération sur les arguments renvoyant une valeur >

L'expression renvoyée par la fonction lambda peut être affectée à une variable et utilisée à plusieurs endroits dans le code.

from typing import Callableajouter : Callable [[ int ], int ] = lambda a : a + a print ( ajouter ( 20 )) # affiche 40

Un autre exemple serait de trier les éléments d'une liste par le nom de leur classe (en Python, tout a une classe) :

a : list [ int | str ] = [ 10 , "number" , 11.2 ] a . sort ( key = lambda x : x . __class__ . __name__ ) print ( a ) # affiche [11.2, 10, 'number']

Notez que 11.2la classe a pour nom " float", 10la classe a pour nom " int", et 'number'la classe a pour nom " str". L'ordre de tri est " float", " int", puis " str".

Fermetures

Les fermetures sont des fonctions évaluées dans un environnement contenant des variables liées . L'exemple suivant lie la variable « seuil » à une fonction anonyme qui compare les valeurs d'entrée à ce seuil.

def comp ( threshold : int ) -> Callable [[ int ], bool ]: return lambda x : x < threshold

Cela peut servir de générateur de fonctions de comparaison :

func_a : Callable [[ int ], bool ] = comp ( 10 ) func_b : Callable [[ int ], bool ] = comp ( 20 )print ( func_a ( 5 ), func_a ( 8 ), func_a ( 13 ), func_a ( 21 )) # affiche True True False Falseprint ( func_b ( 5 ), func_b ( 8 ), func_b ( 13 ), func_b ( 21 )) # affiche True True True False

Il serait impraticable de créer une fonction pour chaque fonction de comparaison possible et il serait peut-être trop contraignant de conserver le seuil pour une utilisation ultérieure. Quelle que soit la raison pour laquelle une fermeture est utilisée, la fonction anonyme est l'entité qui contient la fonctionnalité de comparaison.

curry

La curryfication transforme une fonction à plusieurs arguments en une séquence de fonctions acceptant chacune un seul argument. Dans cet exemple, une fonction effectuant la division par un entier quelconque est transformée en une fonction effectuant la division par un entier donné.

def divide ( x : int , y : int ) -> float : return x / ydef diviseur ( d : int ) -> Callable [[ int ], float ]: return lambda x : divide ( x , d )demi : Callable [[ int ], float ] = divisor ( 2 ) troisième : Callable [[ int ], float ] = divisor ( 3 )print ( half ( 32 ), third ( 32 )) # affiche 16.0 10.666666666666666print ( half ( 40 ), third ( 40 )) # affiche 20.0 13.3333333333333334

Bien que l'utilisation de fonctions anonymes soit peu courante avec la curryfication, elle reste possible. Dans l'exemple ci-dessus, la fonction `divisor` génère des fonctions avec un diviseur spécifié. Les fonctions `half` et `third` curryfient la fonction `divide` avec un diviseur fixe.

La fonction diviseur forme également une fermeture en liant la variable d.

Fonctions d'ordre supérieur

Une fonction d'ordre supérieur est une fonction qui prend une autre fonction comme argument ou qui en renvoie une. Cette technique est fréquemment utilisée pour adapter le comportement d'une fonction générique, comme une boucle ou un modèle récursif. Les fonctions anonymes permettent de spécifier facilement de tels arguments. Les exemples suivants sont en Python 3.

Carte

La fonction map applique une fonction à chaque élément d'une liste. L'exemple suivant met au carré chaque élément d'un tableau à l'aide d'une fonction anonyme.

a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ( list ( map ( lambda x : x * x , a ))) # affiche [1, 4, 9, 16, 25, 36]

La fonction anonyme prend un argument et renvoie son carré. La forme ci-dessus est déconseillée par les créateurs du langage, qui affirment que la forme présentée ci-dessous a la même signification et est plus conforme à la philosophie du langage :

a : liste [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ([ x * x for x in a ]) # affiche [1, 4, 9, 16, 25, 36]

Filtre

La fonction filter renvoie tous les éléments d'une liste qui sont évalués à True lorsqu'ils sont passés à une certaine fonction.

a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ( list ( filter ( lambda x : x % 2 == 0 , a ))) # affiche [2, 4, 6]

La fonction anonyme vérifie si l'argument qui lui est passé est pair. Comme pour `map`, la forme ci-dessous est considérée comme plus appropriée :

a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ([ x for x in a if x % 2 == 0 ]) # affiche [2, 4, 6]

Pli

La fonction `fold` parcourt tous les éléments d'une structure (pour les listes, généralement de gauche à droite, on parle de « fold à gauche » reduceen Python), en accumulant une valeur au fur et à mesure. Elle permet par exemple de combiner tous les éléments d'une structure en une seule valeur :

a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 ] print ( functools . reduce ( lambda x , y : x * y , a )) # affiche 120

Cela fonctionne

La fonction anonyme ici est la multiplication des deux arguments.

La fonction `fold` ne produit pas nécessairement une seule valeur scalaire ; elle peut également générer des résultats structurés, tels que des listes. En effet, les fonctions `map` et `filter` peuvent être créées à partir de `fold`. Dans `map`, la valeur accumulée est une nouvelle liste contenant les résultats de l'application d'une fonction à chaque élément de la liste originale. Dans `filter`, la valeur accumulée est une nouvelle liste contenant uniquement les éléments qui correspondent à la condition donnée.

Liste des langues

Voici une liste des langages de programmation qui prennent en charge les fonctions anonymes sans nom, soit intégralement, soit partiellement sous une forme variante, soit pas du tout.

Le tableau suivant illustre plusieurs schémas courants. Notamment, les langages comme C , Pascal et Object Pascal — qui ne prennent traditionnellement pas en charge les fonctions anonymes — sont tous des langages statiquement typés . Cependant, les langages statiquement typés peuvent prendre en charge les fonctions anonymes. Par exemple, les langages ML sont statiquement typés et incluent fondamentalement des fonctions anonymes, et Delphi , un dialecte d' Object Pascal , a été étendu pour prendre en charge les fonctions anonymes, tout comme C++ (par la norme C++11 ). Deuxièmement, les langages qui traitent les fonctions comme des fonctions de première classe ( Dylan , Haskell , JavaScript , Lisp , ML , Perl , Python , Ruby , Scheme ) prennent généralement en charge les fonctions anonymes afin que les fonctions puissent être définies et manipulées aussi facilement que d'autres types de données.

Examples