Il post del blog che si menziona riguarda più gli aspetti matematici dei tipi di dati algebrici che riguardano il loro utilizzo pratico nella programmazione. Penso che molti programmatori funzionali abbiano prima imparato a conoscere i tipi di dati algebrici usandoli in qualche linguaggio di programmazione, e solo successivamente hanno studiato le loro proprietà algebriche.
Infatti, l'intento del post sul blog è chiaro fin dal suo inizio:
In questa serie di post ti spiego il perché i tipi di dati di Haskell sono chiamati algebrica - senza menzionare la teoria delle categorie o avanzato matematica.
In ogni caso, l'utilità pratica dei tipi algebrici è meglio apprezzata giocando con loro.
Supponiamo, ad esempio, di voler scrivere una funzione per intersecare due segmenti su un piano.
def intersect(s1: Segment, s2: Segment): ???
Quale dovrebbe essere il risultato? Si è tentati di scrivere
def intersect(s1: Segment, s2: Segment): Point
ma cosa succede se non ci sono intersezioni? Si potrebbe tentare di applicare una patch a tale angolo restituendo null
o lanciando un'eccezione NoIntersection
. Tuttavia, due segmenti potrebbero anche sovrapporsi a più di un punto, quando si trovano sulla stessa linea retta. Cosa dovremmo fare in questi casi? Lanciare un'altra eccezione?
L'approccio tipi algebrici è quello di progettare un tipo che copre tutti i casi:
sealed trait Intersection
case object NoIntersection extends Intersection
case class SinglePoint(p: Point) extends Intersection
case class SegmentPortion(s: Segment) extends Intersection
def intersect(s1: Segment, s2: Segment): Intersection
ci sono molti casi pratici in cui tale approccio si sente del tutto naturale. In alcune altre lingue prive di tipi algebrici, è necessario ricorrere alle eccezioni, a null
s (vedere anche the billion-dollar mistake), a classi non sigillate (rendendo impossibile per il compilatore verificare l'esaustività della corrispondenza del modello) o ad altre funzionalità fornite dalla lingua Probabilmente, l'opzione "migliore" in OOP è usare lo Visitor pattern per codificare i tipi algebrici e la corrispondenza dei pattern in lingue che non hanno tali caratteristiche.Tuttavia, avere questo direttamente supportato nella lingua, come in scala, è molto più conveniente.
Si desidera che le tuple restituiscano più di un risultato e si desidera che i tipi di somma facciano le scelte esplicite. (ovviamente questa è solo la prima goccia nell'oceano - puoi scrivere libri su questa roba). Il link che hai dato è forse fuorviante - potresti avere l'idea che hai bisogno di questa roba solo per le cose avory-tower-arkane-magic ma è davvero solo un modo per gestire i tuoi dati in modo sano (specialmente se non hai classi e riferimenti di ereditarietà e mutazione a tua disposizione) – Carsten
@Carsten Sento che capisci di cosa sono confuso. Apprezzato il tuo commento e spero che tu possa dire qualcosa di più :) – Freewind
Solo per esprimere l'avviso che l'acronimo "ADT" è usato anche per significare "Abstract Data Type", che è un concetto opposto a "Algebraic Data Type". L'acronimo "ADT" dovrebbe quindi essere usato con cautela, vale a dire, non del tutto. – pigworker