Funzioni di prima classe
Un'altra funzionalità utile che un linguaggio di programmazione può avere è funzioni di prima classe. Una funzione di prima classe è una funzione che può essere utilizzata come dati.
In una lingua in cui è possibile trattare le funzioni come dati, è possibile creare variabili che si riferiscono ad esse, passarle come argomenti per le funzioni e restituirle dalle funzioni. Una volta che il caso in cui potresti utilizzare questa è la famosa funzione map
.
Diciamo che ho appena ottenuto una stringa da un file o qualcosa e che la stringa contiene una serie di numeri interi separati da spazi. Supponiamo che io usi una funzione di divisione delle stringhe per ottenere un array di stringhe contenenti ciascuno degli interi (sempre come stringhe). Ho accesso a una funzione di libreria per analizzare un intero da una stringa, e voglio usarlo per convertire ciascuna di queste stringhe contenenti numeri interi a valori interi reali. Creo il nuovo array e scrivo un loop per convertire ogni stringa e memorizzare il numero intero risultante nel nuovo array.
Ora dì che voglio prendere una diversa matrice di numeri interi e trovare il valore assoluto di ciascuno e memorizzare i risultati in una nuova matrice. Posso usare un altro ciclo per farlo. Tuttavia, ho questo modello visualizzato nel mio codice: iniziare con un array, eseguire alcune trasformazioni di ogni valore nell'array e memorizzare tutti i risultati in un nuovo array. Potrei semplicemente scrivere il codice per farlo ogni volta, ma c'è un modo per astrarre il processo di creazione del nuovo array, il looping, la trasformazione e l'archiviazione.
Posso scrivere una funzione che accetta come argomenti
- un array di tipo x
- una funzione per trasformare in qualche modo oggetti di tipo x in oggetti di tipo y (possibilmente dello stesso tipo di x)
e fargli creare una serie di elementi di tipo y della lunghezza corretta, eseguire il loop sui valori nell'array originale, chiamare l'argomento della funzione per eseguire la trasformazione , archiviare i risultati nella nuova array e restituisce il nuovo array.
Dopo aver scritto questa funzione, map
, non devo più scrivere questo codice a mano.
L'obiettivo-C dovrebbe avere dei puntatori di funzione perché ce li ha.
Il modo in cui ho descritto map
ha anche sfruttato una sorta di digitazione generica.
Chiusure
Un'altra caratteristica sono le chiusure. Una chiusura è un oggetto funzione che cattura alcune delle variabili esistenti nello scope in cui è stato creato. Cosa significa?
Alcune lingue ti permettono di scrivere letterali di funzioni, funzioni che non hanno (necessariamente) nomi e appaiono semplicemente nel tuo codice senza una speciale dichiarazione separata. Quando scrivi una funzione letterale in un'altra funzione, potrebbero esserci variabili nello stesso ambito della funzione letterale. Ci sono situazioni in cui potresti trovare utile usare quelle variabili all'interno della funzione letterale e farle rimanere con l'oggetto funzione. Tale oggetto funzione sarebbe una chiusura.
Ecco un esempio di codice che ho scritto che crea una chiusura (scritta in Common Lisp):
(defun exponential-change (function constant)
(lambda (time)
(* (expt constant time) (funcall function time))))
(Do not ((let (the) parentesi) ti spaventano)). Pensa che sia scritto in questo modo:
function exponential_change (function, constant) {
return function (time) {
return exponent(constant, time) * function(time);
};
}
Ho scritto questo per sintetizzare il suono. Io rappresento un suono in funzione del tempo che restituisce campioni di ampiezza (da -1 a 1). Questa funzione, exponential-change
, trasforma un suono aumentando o diminuendo l'ampiezza (in base alla costante) in modo esponenziale. exponential-change
crea restituisce una funzione del tempo basata su un'altra funzione del tempo. Il fatto che la nuova funzione tenga traccia di quale funzione debba modificare impedisce ad altri codici di tenere traccia di quel dettaglio.
Le chiusure non solo tengono traccia dei valori delle variabili che catturano ma anche delle variabili stesse. Ciò significa che potresti creare una funzione che modifica quelle variabili.