Les valeurs peuvent être des chiffres ou d'autres types de données, comme des lettres, ou des structures de données composées de parties plus simples. Dans les règles d'un langage de programmation, les valeurs de première classe sont des valeurs qui peuvent être données à des fonctions, renvoyées par des fonctions et liées à un nom de variable. Les fonctions qui prennent ou renvoient d'autres fonctions sont appelées fonctions d'ordre supérieur. La plupart des langages qui ont des fonctions comme valeurs de première classe ont également des fonctions d'ordre supérieur et des fermetures.
Par exemple, jetez un coup d'œil à la fonction suivante du régime :
Renvoyer une liste de tous les livres dont au moins un exemplaire a été vendu. (définir (seuil de best-sellers) (filtre (lambda (livre) (>= (seuil de best-sellers)) liste de livres))
Dans cet exemple, l'expression lambda (lambda (livre) (>= seuil de vente de livres)) fait partie de la fonction best-sellers de livres. Lorsque la fonction est exécutée, Scheme doit faire la valeur du lambda. Il le fait en faisant une fermeture avec le code du lambda et une référence à la variable seuil, qui est une variable libre à l'intérieur du lambda. (Une variable libre est un nom qui n'est pas lié à une valeur).
La fonction de filtrage effectue ensuite la fermeture de chaque livre de la liste pour choisir les livres à retourner. Comme la fermeture elle-même a une référence à un seuil, la fermeture peut utiliser cette valeur chaque fois que le filtre exécute la fermeture. La fonction de filtrage elle-même peut être écrite dans un fichier complètement séparé.
Voici le même exemple réécrit en ECMAScript (JavaScript), un autre langage populaire qui supporte les fermetures :
// Retourne une liste de tous les livres ayant au moins un "seuil" d'exemplaires vendus. function bestSellingBooks(threshold) { return bookList. filter( function(book) { return book. sales >= threshold ; } ) ; }
ECMAScript utilise ici le mot fonction au lieu de lambda, et la méthode Array.filter à la place de la fonction de filtrage, mais sinon le code fait la même chose de la même manière.
Une fonction peut créer une fermeture et la rendre. L'exemple suivant est une fonction qui renvoie une fonction.
Dans Scheme :
Retourne une fonction qui se rapproche de la dérivée de f ; en utilisant un intervalle de dx, qui doit être suffisamment petit. (définir (dérivée f dx) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))
En ECMAScript :
// renvoie une fonction qui se rapproche de la dérivée de f // en utilisant un intervalle de dx, qui doit être suffisamment petit. function derivative(f, dx) { return function(x) { return (f(x + dx) - f(x)) / dx ; } ; }
L'environnement de fermeture conserve les variables liées f et dx après le retour de la fonction de fermeture (dérivée). Dans les langues sans fermeture, ces valeurs seraient perdues après le retour de la fonction de fermeture. Dans les langages avec fermetures, une variable liée doit être conservée en mémoire aussi longtemps qu'une fermeture la possède.
Il n'est pas nécessaire que la fermeture soit faite en utilisant une fonction d'anonymat. Le langage de programmation Python, par exemple, ne supporte que de façon limitée les fonctions anonymes mais dispose de fermetures. Par exemple, l'exemple ECMAScript ci-dessus pourrait être implémenté en Python d'une certaine manière :
# Retourne une fonction qui se rapproche de la dérivée de f # en utilisant un intervalle de dx, qui doit être suffisamment petit. def derivative(f, dx) : def gradient(x) : return (f(x + dx) - f(x)) / dx gradient de retour
Dans cet exemple, la fonction appelée gradient fait une fermeture avec les variables f et dx. La fonction de fermeture extérieure nommée derivative renvoie cette fermeture. Dans ce cas, une fonction anonyme fonctionnerait également.
def derivative(f, dx) : return lambda x : (f(x + dx) - f(x)) / dx
Python doit souvent utiliser des fonctions nommées à la place car ses expressions lambda peuvent ne contenir que d'autres expressions (code qui renvoie une valeur) et non des instructions (code qui a des effets mais pas de valeur). Mais dans d'autres langages, tels que Scheme, tout code renvoie une valeur ; dans Scheme, tout est une expression.