Funzioni di ordine superiore

Swift

I linguaggi di programmazione che ammettono funzioni che possono essere passate come parametro ad altre funzioni si dicono linguaggi che ammettono funzioni di ordine superiore.

Alcune funzioni di ordine superiore in Swift

Swift, ovviamente, ammette funzioni di ordine superiore e in questo articolo ne vediamo 3 già definite dal linguaggio: filter, map e reduce.

Filter

Cominciamo con un semplice esempio e supponiamo di avere un array di 10 elementi interi:

let numbers = [21, 45, 38, 32, 11, 98, 43, 9, 52, 61] 

Supponiamo ora di voler ottenere un array contente solamente i numeri minori o uguali di 30.
Generalmente questo semplice passaggio si farebbe con un ciclo for ed un nuovo array:

var filteredNumbers = [Int]()

for number in numbers {
    if number <= 30 {
        filteredNumbers.append(number)
    }
}

Non è sbagliato, ma qualcuno potrebbe ritenere questo approccio un po’ troppo verboso, inoltre si potrebbe anche argomentare che da un punto di vista logico avere un filteredNumbers dichiarato come variabile, permetterebbe di aggiungere nuovi elementi vanificando così il suo scopo, infatti è consentito eseguire:

filteredNumbers.append(45)

Quale altra soluzione abbiamo?
Qui entrano in gioco le funzioni di ordine superiore cioè funzioni che possono accettare come parametro un’altra funzione che prende il nome di funzione anonima o closure.

Nel nostro esempio, possiamo usare il metodo filter che invocato su un array, consente di ottenere un nuovo array in cui gli elementi sono selezionati sulla base di una logica che deve essere flessibile per incontrare ogni esigenza e cioè variabile.

let filteredNumbers = numbers.filter({ $0 <= 30 })

Analizziamo cosa succede.
Il metodo filter, accetta come parametro una funzione anonima (o closure).
Una funzione anonima è una funzione senza nome, quindi ha solo il blocco di codice, ed in swift i blocchi di codice sono racchiusi dalle parentesi graffe { ... }.
In maniera più esplicita la nostra funzione anonima sarebbe:

(value: Int) -> Bool { return value <= 30 }

Accetta un parametro value di tipo Int e ritorna un valore Bool
Per farla breve, nel caso delle closure, il tipo di ritorno può essere determinato dal valore di ritorno (si usa spesso, pensiamo alla dichiarazione del nostro array numbers, non abbiamo specificato che è un array di tipo int anche se avessimo potuto farlo) quindi non esplicitiamo il tipo di ritorno e nemmeno lo statement return:

(value: Int) { value <= 30 }

mentre i parametri possono non avere nome ed essere identificati da $0, $1, $2, ecc… a second della loro posizione, così possiamo condensare in:

{ $0 <= 30 }

Ed ecco ottenuta la closure che implementa la nostra logica di selezione da passare come parametro al metodo filter.

Map

Pensiamo ora al caso in cui vogliamo ottenere un array in cui i valori sono trasformati applicando un calcolo, per esempio moltiplicarli per 2.
Ancora una volta, in maniera banale potremmo usare un ciclo for:

var multipliedNumbers = [Int]()

for number in numbers {
    multipliedNumbers.append(number*2)
}

Anche in questo caso possiamo utilizzare una funzione di ordine superiore già pronta per noi:

let otherMultipliedNumbers = numbers.map({ $0 * 2 })

Il funzionamento è molto simile alla filter in quanto agisce su un solo valore

Reduce

L’ultimo esempio è il caso in cui da un insieme di valori vogliamo ottenere un valore unico, esempio la media dei valori

var sum: Int = 0

for number in numbers {
    sum += number
}

let mean = sum/numbers.count

In questo caso possiamo usare la funzione reduce:

let sum = numbers.reduce(0, { $0 + $1 })
let mean = sum/numbers.count

La funzione reduce richiede due parametri, il primo è il valore di partenza del risultato, il secondo è la closure che determina l’incremento del valore di partenza alla quale vengono passati 2 parametri: $0 è il valore di partenza (incrementato ad ogni iterazione), il secondo, $1, è il valore di numbers corrente.

Conclusioni

Abbiamo visto cosa sono e perchè usare le funzioni di ordine superiore e alcuni metodi che le utilizzano.

A questo link: https://github.com/giacomopiva/Swift-PlayGrounds.git trovate il repository che contiene tutti i playgroind degli esempi compreso quello di questo articolo (HOF.playground)

Condividi se ti è piaciuto

Leggi altri articoli