TL; DR Comme d'autres l'ont souligné: la notation lambda est simplement un moyen de définir des fonctions sans être obligé de leur donner un nom.
Version longue
Je voudrais élaborer un peu sur ce sujet parce que je le trouve très intéressant. Disclaimer: J'ai suivi mon cours de lambda calcul il y a longtemps. Si une personne mieux informée trouve des inexactitudes dans ma réponse, n'hésitez pas à m'aider à l'améliorer.
Commençons par les expressions, par exemple 1 + 2
et x + 2
. Les littéraux tels que 1
et 2
sont appelés des constantes car ils sont liés à des valeurs fixes spécifiques.
Un identifiant tel que celui x
appelé variable et afin de l’évaluer, vous devez d’abord le lier à une valeur. Donc, fondamentalement, vous ne pouvez pas évaluer x + 1
tant que vous ne savez pas ce que x
c'est.
La notation lambda fournit un schéma permettant de lier des valeurs d’entrée spécifiques à des variables. Une expression lambda peut être formée en ajoutant λx .
devant une expression existante, par exemple λx . x + 1
. Variable x
est dit être libre dans x + 1
et lié àλx . x + 1
Comment cela aide-t-il à évaluer les expressions? Si vous introduisez une valeur dans l'expression lambda, comme ceci
(λx . x + 1) 2
alors vous pouvez évaluer l'expression entière en remplaçant (reliant) toutes les occurrences de la variable x
par la valeur 2:
(λx . x + 1) 2
2 + 1
3
Ainsi, la notation lambda fournit un mécanisme général pour lier des éléments à des variables qui apparaissent dans un bloc d'expression / programme. Selon le contexte, cela crée des concepts très différents dans les langages de programmation:
- Dans un langage purement fonctionnel comme Haskell, les expressions lambda représentent des fonctions au sens mathématique: une valeur d'entrée est injectée dans le corps du lambda et une valeur de sortie est produite.
- Dans de nombreuses langues (JavaScript, Python, Scheme, par exemple), l’évaluation du corps d’une expression lambda peut avoir des effets secondaires. Dans ce cas, on peut utiliser le terme procédure pour marquer la différence par rapport aux fonctions pures.
Outre les différences, la notation lambda consiste à définir des paramètres formels et à les lier à des paramètres réels.
La prochaine étape consiste à donner un nom à une fonction / procédure. Dans plusieurs langues, les fonctions sont des valeurs comme toutes les autres, vous pouvez donc nommer une fonction comme suit:
(define f (lambda (x) (+ x 1))) ;; Scheme
f = \x -> x + 1 -- Haskell
val f: (Int => Int) = x => x + 1 // Scala
var f = function(x) { return x + 1 } // JavaScript
f = lambda x: x + 1 # Python
Comme Eli Barzilay l'a souligné, ces définitions ne font que lier le nom f
à une valeur, qui se trouve être une fonction. Ainsi, à cet égard, les fonctions, les nombres, les chaînes, les caractères sont des valeurs pouvant être liées à des noms de la même manière:
(define n 42) ;; Scheme
n = 42 -- Haskell
val n: Int = 42 // Scala
var n = 42 // JavaScript
n = 42 # Python
Dans ces langues, vous pouvez également associer une fonction à un nom en utilisant la notation plus connue (mais équivalente):
(define (f x) (+ x 1)) ;; Scheme
f x = x + 1 -- Haskell
def f(x: Int): Int = x + 1 // Scala
function f(x) { return x + 1 } // JavaScript
def f(x): return x + 1 # Python
Certaines langues, par exemple C, ne supportent cette dernière notation que pour définir des fonctions (nommées).
Fermetures
Quelques observations finales concernant les fermetures . Considérez l'expression x + y
. Ceci contient deux variables libres. Si vous vous liez en x
utilisant la notation lambda, vous obtenez:
\x -> x + y
Ce n'est pas (encore) une fonction car elle contient toujours une variable libre y
. Vous pouvez en faire une fonction en liant y
également:
\x -> \y -> x + y
ou
\x y -> x + y
ce qui est identique à la +
fonction.
Mais vous pouvez lier, par exemple, y
d’une autre manière (*):
incrementBy y = \x -> x + y
Le résultat de l'application de la fonction incrementBy à un nombre est une fermeture, c'est-à-dire une fonction / procédure dont le corps contient une variable libre (par exemple y
) qui a été liée à une valeur de l'environnement dans lequel la fermeture a été définie.
Il en incrementBy 5
va de même pour la fonction (fermeture) qui incrémente les nombres de 5.
REMARQUE (*)
Je triche un peu ici:
incrementBy y = \x -> x + y
est équivalent à
incrementBy = \y -> \x -> x + y
donc le mécanisme de liaison est le même. Intuitivement, je pense qu'une fermeture représente une partie d'une expression lambda plus complexe. Lorsque cette représentation est créée, certaines des liaisons de l'expression mère ont déjà été définies et la fermeture les utilise ultérieurement lors de son évaluation / invocation.