I valori possono essere numeri o qualche altro tipo di dati, come le lettere, o strutture di dati composte da parti più semplici. Nelle regole di un linguaggio di programmazione, i valori di prima classe sono valori che possono essere dati alle funzioni, restituiti dalle funzioni e legati a un nome di variabile. Le funzioni che prendono o restituiscono altre funzioni sono chiamate funzioni di ordine superiore. La maggior parte dei linguaggi che hanno funzioni come valori di prima classe hanno anche funzioni di ordine superiore e chiusure.
Per esempio, date un'occhiata alla seguente funzione Scheme:
; Restituisce un elenco di tutti i libri con almeno THRESHOLD copie vendute. (define (best-selling-books threshold) (filter (lambda (book) (>= (book-sales book) threshold)) book-list))
In questo esempio, l'espressione lambda (lambda (book) (>= (book-sales book) threshold)) fa parte della funzione best-selling-books. Quando la funzione viene eseguita, Scheme deve rendere il valore della lambda. Lo fa creando una chiusura con il codice della lambda e un riferimento alla variabile soglia, che è una variabile libera all'interno della lambda. (Una variabile libera è un nome che non è legato ad un valore).
La funzione filtro esegue quindi la chiusura su ogni libro della lista per scegliere quali libri restituire. Poiché la chiusura stessa ha un riferimento alla soglia, la chiusura può usare quel valore ogni volta che filter esegue la chiusura. La funzione filtro stessa potrebbe essere scritta in un file completamente separato.
Ecco lo stesso esempio riscritto in ECMAScript (JavaScript), un altro linguaggio popolare con supporto per le chiusure:
// Restituisce un elenco di tutti i libri con almeno 'soglia' di copie vendute. function bestSellingBooks(soglia) { return bookList. filter( function(book) { return book. sales >= soglia; } ); }
ECMAScript usa la parola function qui invece di lambda, e il metodo Array.filter al posto della funzione filter, ma per il resto il codice fa la stessa cosa nello stesso modo.
Una funzione può creare una chiusura e restituirla. L'esempio seguente è una funzione che restituisce una funzione.
In Schema:
(definire (derivata f dx) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))
In ECMAScript:
// restituisce una funzione che approssima la derivata di f // usando un intervallo di dx, che dovrebbe essere opportunamente piccolo. function derivative(f, dx) { return function(x) { return (f(x + dx) - f(x)) / dx; }; }
L'ambiente di chiusura mantiene le variabili vincolate f e dx dopo il ritorno della funzione di chiusura (derivata). Nei linguaggi senza chiusure, questi valori verrebbero persi dopo il ritorno della funzione di chiusura. Nei linguaggi con le chiusure, una variabile vincolata deve essere mantenuta in memoria finché qualsiasi chiusura la possiede.
Una chiusura non deve necessariamente essere formata usando una funzione anonima. Il linguaggio di programmazione Python, per esempio, ha un supporto limitato per le funzioni anonime ma ha le chiusure. Per esempio, un modo in cui l'esempio ECMAScript di cui sopra potrebbe essere implementato in Python è:
# Restituisce una funzione che approssima la derivata di f # usando un intervallo di dx, che dovrebbe essere opportunamente piccolo. def derivata(f, dx): def gradiente(x): return (f(x + dx) - f(x)) / dx return gradiente
In questo esempio, la funzione chiamata gradiente crea una chiusura insieme alle variabili f e dx. La funzione esterna chiusa chiamata derivata restituisce questa chiusura. In questo caso, funzionerebbe anche una funzione anonima.
def derivata(f, dx): return lambda x: (f(x + dx) - f(x)) / dx
Python deve spesso usare funzioni nominate invece perché le sue espressioni lambda possono contenere solo altre espressioni (codice che restituisce un valore) e non dichiarazioni (codice che ha effetti ma nessun valore). Ma in altri linguaggi, come Scheme, tutto il codice restituisce un valore; in Scheme, tutto è un'espressione.