Esplorare le funzioni
Spesso ci si trova in una situazione in cui il codice appare ripetitivo. Esegue la stessa cosa in molti luoghi o ci sono solo differenze minori. In situazioni come queste, è consigliabile riflettere su come rendere riutilizzabile il codice. Il modo corretto per affrontare questa situazione consiste nell'estrarre le espressioni e creare una o più funzioni. Una funzione è un blocco predefinito fondamentale in numerosi linguaggi di programmazione ed F# non fa eccezione.
Una funzione
Una funzione è un riferimento denominato che ha un corpo costituito da una o più espressioni. Una funzione può anche avere parametri. Una funzione inizia con la parola chiave let e il nome della funzione. È quindi presente un operatore di assegnazione e, alla sua destra, il corpo della funzione.
Ecco la sintassi di una funzione:
let <function name> <parameters> = <function body>
Un esempio di effettiva funzione, mostrato nell'esempio precedente, sarà simile al seguente:
let add a b = a + b
In questo esempio, il nome della funzione è add e i parametri sono a e b. Il corpo della funzione aggiunge i due parametri insieme,a+b, e restituisce il risultato.
Valori restituiti
Come si è osservato nel primo esempio, non è presente alcuna parola chiave return per specificare che cosa restituire. In F# le informazioni nell'ultima riga di una funzione corrispondono a quello che viene restituito. Si consideri questa funzione su più righe:
let addAndMultiply a b c =
let sum = a + b
let product = sum * c
product
Inserendo product nell'ultima riga, la funzione specifica che cosa viene restituito. Come si chiama una funzione come questa?
Chiamare una funzione
Per chiamare o richiamare una funzione, usare il nome della funzione e aggiungere tutti i parametri che si vogliono usare, separati da uno spazio. Ad esempio, per chiamare la funzione addAndMultiply(), immettere il codice seguente:
addAndMultiply 2 3 3 // 15
Per visualizzare i risultati della funzione, è possibile assegnarla a una variabile o stamparla direttamente in questo modo:
let sum = addAndMultiply 2 3 3
printfn "%i" sum
// OR
printfn "%i" (addAndMultiply 2 3 3)
Tipi dedotti
Si prenda il codice seguente:
let add a b = a + b
let sum = add 2 2
let concat = add "hello" "world" // will give compilation error
Questo codice si interrompe all'ultima riga con il seguente messaggio:
error FS0001: This expression was expected to have type
'int'
but here has type
'string'
Il motivo dell'errore è che F# ha già determinato il tipo di parametro da usare e ha optato per Integer. Il motivo per cui ha deciso di usare Integer è dovuto alle informazioni nella seconda riga, let sum = add 2 2. La funzione add() è stata usata in un modo che indica che il tipo di parametro era sicuramente Integer.
Se la seconda riga non esiste, il codice funziona:
let add a b = a + b
// let sum = add 2 2
let concat = add "hello" "world" // will work
Il compilatore osserva che il primo uso della funzione avviene con stringhe e conclude quindi che il tipo di parametro è una stringa. Quindi, contesto e primo utilizzo sono utili per dedurre il tipo.
Tipi espliciti
Esistono situazioni in cui si vuole essere espliciti, sia per quanto riguarda i tipi di parametri accettati che i valori restituiti dalla funzione. Un approccio più specifico consente di migliorare la leggibilità, anche se molto probabilmente il compilatore non ne ha bisogno.
Si consideri ad esempio la funzione seguente:
let convert a =
int a
Per aggiungere tipi alla funzione, è necessario aggiungere :<type> in questo modo:
let convert (a:string) =
int a
Il parametro ha ora il tipo string tramite il codice let convert (a:string). È ora possibile essere ancora più espliciti aggiungendo un tipo di ritorno. A questo scopo, aggiungere un altro parametro :<type> subito dopo il parametro:
let convert (a:string) :int =
int a
Il parametro è ora racchiuso tra parentesi, come mostrato in (a:string). Il tipo restituito è l'ultima annotazione :<type> presentata, ovvero :int. F# è sufficientemente intelligente da interpretare la maggior parte degli scenari, ma a volte è necessario contribuire, rendendo più esplicito il codice. Un altro vantaggio dell'aggiunta dei tipi è che rende più semplice la comprensione del codice per un altro sviluppatore.