Julia Language
Funzioni di ordine superiore
Ricerca…
Sintassi
- foreach (f, xs)
- mappa (f, xs)
- filtro (f, xs)
- ridurre (f, v0, xs)
- foldl (f, v0, xs)
- foldr (f, v0, xs)
Osservazioni
Le funzioni possono essere accettate come parametri e possono anche essere prodotte come tipi di ritorno. In effetti, le funzioni possono essere create all'interno del corpo di altre funzioni. Queste funzioni interiori sono note come chiusure .
Funziona come argomenti
Le funzioni sono oggetti in Julia. Come qualsiasi altro oggetto, possono essere passati come argomenti ad altre funzioni. Le funzioni che accettano le funzioni sono conosciute come funzioni di ordine superiore .
Ad esempio, possiamo implementare un equivalente della funzione foreach
della libreria standard prendendo una funzione f
come primo parametro.
function myforeach(f, xs)
for x in xs
f(x)
end
end
Possiamo verificare che questa funzione funzioni effettivamente come ci aspettiamo:
julia> myforeach(println, ["a", "b", "c"])
a
b
c
Prendendo una funzione come primo parametro, invece di un parametro successivo, possiamo usare la sintassi del blocco Do di Julia. La sintassi del blocco do è solo un modo conveniente per passare una funzione anonima come primo argomento di una funzione.
julia> myforeach([1, 2, 3]) do x
println(x^x)
end
1
4
27
La nostra implementazione di myforeach
sopra è approssimativamente equivalente alla funzione foreach
integrata. Esistono anche molte altre funzioni di ordine superiore incorporate.
Le funzioni di ordine superiore sono piuttosto potenti. A volte, quando si lavora con funzioni di ordine superiore, le operazioni esatte eseguite diventano irrilevanti e i programmi possono diventare piuttosto astratti. I combinatori sono esempi di sistemi di funzioni di ordine superiore altamente astratte.
Mappare, filtrare e ridurre
Due delle funzioni di ordine superiore più fondamentali incluse nella libreria standard sono la map
e il filter
. Queste funzioni sono generiche e possono funzionare su qualsiasi iterabile . In particolare, sono adatti per i calcoli sugli array .
Supponiamo di avere un set di dati delle scuole. Ogni scuola insegna un argomento particolare, ha un numero di classi e un numero medio di studenti per classe. Possiamo modellare una scuola con il seguente tipo immutabile :
immutable School
subject::Symbol
nclasses::Int
nstudents::Int # average no. of students per class
end
Il nostro set di dati delle scuole sarà una Vector{School}
:
dataset = [School(:math, 3, 30), School(:math, 5, 20), School(:science, 10, 5)]
Supponiamo di voler trovare il numero totale di studenti iscritti a un programma di matematica. Per fare ciò, sono necessari diversi passaggi:
- dobbiamo restringere il set di dati solo alle scuole che insegnano la matematica (
filter
) - dobbiamo calcolare il numero di studenti in ogni scuola (
map
) - e dobbiamo ridurre quella lista di numeri di studenti a un singolo valore, la somma (
reduce
)
Una soluzione ingenua (non molto performante) sarebbe semplicemente quella di utilizzare direttamente quelle tre funzioni di ordine superiore.
function nmath(data)
maths = filter(x -> x.subject === :math, data)
students = map(x -> x.nclasses * x.nstudents, maths)
reduce(+, 0, students)
end
e verifichiamo che ci sono 190 studenti di matematica nel nostro set di dati:
julia> nmath(dataset)
190
Esistono delle funzioni per combinare queste funzioni e quindi migliorare le prestazioni. Ad esempio, avremmo potuto utilizzare la funzione mapreduce
per eseguire la mappatura e la riduzione di un passo, il che farebbe risparmiare tempo e memoria.
La reduce
è significativa solo per le operazioni associative come +
, ma a volte è utile eseguire una riduzione con un'operazione non associativa. L'ordine superiore funzioni foldl
e foldr
sono forniti per forzare un particolare ordine riduzione.