Higher-order functions

Nei linguaggi funzionali, le funzioni sono valori a tutti gli effetti. Ciò significa che esse, come tutti gli altri valori del linguaggio, possono essere:

Dal punto di vista dei tipi, una funzione ha un tipo che stabilisce una correlazione tra gli elementi del dominio e del codominio (in inglese range). In un linguaggio funzionale, questo tipo può essere usato ovunque siano ammessi gli altri tipi. Ciò fornisce meccanismi di composizione delle funzioni estremamente flessibili, che consentono la scritture di codice più elegante, meno prolisso, e un riuso “più furbo” del codice.

Si chiama higher-order function (funzione di ordine superiore o all’ordine superiore) una fnzione che prende una o più funzioni come parametri e/o restituisce una nuova funzione come risultato.

Al fine di illustrare l’utilità delle funzioni di ordine supeiore, e il modo in cui si definiscono e usano in Scala, è utile considerare un esempio. Si supponga di definire una funzione che calcola la sommatoria dei numeri interi compresi tra gli estremi $a$ e $b$ — in simboli, $\sum_{n=a}^b n$. Una semplice implementazione è la seguente:

def sumInts(a: Int, b: Int): Int =
	if (a > b) 0 else a + sumInts(a + 1, b)

Ora, si definiscono anche delle funzioni per calcolare la sommatoria dei quadrati dei numeri, tra $a$ e $b$, $\sum_{n=a}^b n^2$,

def square(x: Int): Int = x * x

def sumSquares(a: Int, b: Int): Int =
	if (a > b) 0 else square(a) + sumSquares(a + 1, b)

e la sommatoria dei fattoriali, $\sum_{n=a}^b n!$:

def factorial(n: Int): Int =
	if (n == 0) 1 else n * factorial(n - 1)

def sumFactorials(a: Int, b: Int): Int =
	if (a > b) 0 else factorial(a) + sumFactorials(a + 1, b)

Confrontando i corpi delle tre funzioni di somma,

Untitled

si osserva che esse sono molto simili, e diventano ancora pù simili se si riscrive sumInts usando la funzione identità id:

def id(x: Int): Int = x

Untitled

l’unica differenza (a parte il nome della funzione usato per la chiamata ricorsiva) è la funzione applciata a ciascun intero nell’intervallo per calcolare il valore da aggiungere alla somma parziale — rispettivamente id, square e factorial. Infatti, queste funzioni calcolano casi particolari della sommatoria $\sum_{n=a}^b f(n)$, con appunto $f(n)=n$ (id), $f(n)=n^2$ (square) e $f(n)=n!$ (factorial).

Il pattern comune così individuato può essere fattorizzato definendo una funzione all’ordine superiore che prende come argomeno la funzione da applicare a ogni intero compreso nell’intervallo. Il tipo del parametro funzione è un tipo funzionale (un tipo i cui valori sono funzioni), che si scrive con la notazione Domain => Range (cioè in questo caso Int => Int), mentre il nome del parametro segue le stesse regole che valgono per i nomi di tutti gli altri parametri formali. La definizione della funzione di ordine superiore è allora: