Tipi Algebrici in F#
I tipi algebrici di F# permettono di risolvere il seguente problema:
Il metodo X deve effettuare un'operazione Y e può ritornare il risultato dell'operazione rappresentato dal Tipo T oppure un messaggio di errore e/o validazione dei dati
La strada che si può utilizzare in C# è quella di racchiudere il risultato dell'operazione in una classe come la seguente
public class Risultato<T> { public bool Successo { get; set; } public string Messaggio { get; set; } public T RisultatoOperazione { get; set; } }
Questo approccio permettere di racchiudere la logica di cui abbiamo bisogno ma non garantisce minimamente che l'utilizzatore del metodo gestisca correttamente il risultato. Un'altra strategia potrebbe essere quella di sollevare un'eccezione piuttosto che ritornare un messaggio di errore ma nuovamente non abbiamo idea se l'utlizzatore del metodo vada a gestire eventuali eccezione e il nostro metodo non suggerisce in alcun modo la presenza di queste eccezione se non tramite la possibilità di documentarle.
I tipi algebrici di cui stiamo parlando sono in particolare gli "union types" ovvero i tipi costruiti a partire da altri tipi con la logica "uno o l'altro". Quindi possiamo cotruire un tipo che sia una stringa, il nostro messaggio, oppure il risultato dell'operazione che stiamo effettuando. Chiunque chiamerà il nostro metodo, per poterlo utilizzare dovrà necessariamente estrarre il valore utilizzando il pattern matching e gestire tutti i casi possibili.
In questo modo ci sarà un controllo in fase di compilazione che tutte le possibilità, risultato o fallimento, vengano gestite. La sintassi di questi tipi è semplicissima, come esempio proviamo ad utilizzarlo per calcolare la divisione tra due interi.
type OpResult = Risultato of int | Messaggio of string let divisione a b = if (b = 0) then Messaggio("Impossibile dividere per zero") else Risultato(a/b) [<EntryPoint>] let main argv = let r = divisione 1 0 match r with | Risultato u -> printfn "%d" u | Messaggio m -> printfn "%s" m 0