Modellazione con gli ADT
Renda gli stati illegali non rappresentabili
Modellazione con gli ADT è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Tipi di dati algebrici
I tipi di dati algebrici (ADT) sono alla base della modellazione funzionale del dominio. Combinano i tipi prodotto (AND) e i tipi somma (OR) per descrivere i dati con precisione.
- Prodotto: un record con diversi campi.
- Somma: una scelta tra diverse varianti.
case class Point(x: Int, y: Int) // product type
object Main:
def main(args: Array[String]): Unit =
println(Point(1, 2))Tipi prodotto
Un tipo prodotto raggruppa più valori. In Scala una case class è un prodotto: un'istanza contiene contemporaneamente tutti i suoi campi.
case class User(name: String, age: Int)
object Main:
def main(args: Array[String]): Unit =
val u = User("Ada", 36)
println(u.name)
println(u.age)Tipi somma
Un tipo somma è un valore che corrisponde esattamente a una tra diverse varianti. Gli enum di Scala 3 lo esprimono direttamente.
enum PaymentMethod:
case Cash
case Card(number: String)
case Crypto(wallet: String)
object Main:
def main(args: Array[String]): Unit =
val p: PaymentMethod = PaymentMethod.Card("1234")
println(p)Rendere irrappresentabili gli stati non validi
Il principio fondamentale è progettare i tipi in modo che i dati non validi non possano nemmeno essere costruiti. Se il sistema dei tipi vieta uno stato errato, non sarà mai necessario verificarlo a runtime.
enum Connection:
case Disconnected
case Connected(sessionId: String)
object Main:
def main(args: Array[String]): Unit =
// No way to have a sessionId while Disconnected
val c: Connection = Connection.Connected("abc")
println(c)Cattiva progettazione e buona progettazione
Un record piatto con campi nullable favorisce gli stati non validi. Modellare ogni caso come una variante li elimina.
- Errato:
case class Conn(connected: Boolean, sessionId: String)consente connected=false con un sessionId. - Corretto: un tipo somma associa il campo allo stato appropriato.
enum Door:
case Open
case Closed
case Locked(key: String)
object Main:
def main(args: Array[String]): Unit =
val d: Door = Door.Locked("k1")
println(d)Combinare prodotti e somme
I modelli reali annidano prodotti nelle somme e viceversa. Ogni variante può contenere il proprio prodotto di campi.
case class Address(city: String, zip: String)
enum Contact:
case Email(value: String)
case Postal(address: Address)
object Main:
def main(args: Array[String]): Unit =
val c: Contact = Contact.Postal(Address("Paris", "75001"))
println(c)Pattern matching sugli ADT
Si usano gli ADT tramite il pattern matching. Poiché il tipo è chiuso, il compilatore avvisa se si omette una variante.
enum Shape:
case Circle(r: Double)
case Rect(w: Double, h: Double)
object Main:
def area(s: Shape): Double = s match
case Shape.Circle(r) => 3.14159 * r * r
case Shape.Rect(w, h) => w * h
def main(args: Array[String]): Unit =
println(area(Shape.Rect(2, 3)))ADT ricorsivi
Gli ADT possono fare riferimento a se stessi, modellando naturalmente alberi, liste ed espressioni.
enum Expr:
case Num(value: Int)
case Add(left: Expr, right: Expr)
object Main:
def eval(e: Expr): Int = e match
case Expr.Num(v) => v
case Expr.Add(l, r) => eval(l) + eval(r)
def main(args: Array[String]): Unit =
val e = Expr.Add(Expr.Num(2), Expr.Num(3))
println(eval(e))Opzionalità con Option
Usi Option invece di null per modellare un campo che potrebbe essere assente. Il tipo rende esplicita l'assenza e impone di gestirla.
case class Profile(name: String, nickname: Option[String])
object Main:
def main(args: Array[String]): Unit =
val p = Profile("Grace", None)
println(p.nickname.getOrElse("(none)"))Modellare le quantità con precisione
Superi la dipendenza eccessiva dai primitivi. Invece di usare Int e String grezzi, racchiuda le quantità significative in tipi che documentano l'intento e impediscono gli scambi.
case class Quantity(value: Int)
case class Price(cents: Long)
case class LineItem(qty: Quantity, price: Price)
object Main:
def main(args: Array[String]): Unit =
val item = LineItem(Quantity(3), Price(500))
println(item)Perché gli ADT sono importanti
Gli ADT offrono correttezza e chiarezza.
- Gli stati non validi non possono essere costruiti.
- Il pattern matching esaustivo rileva i casi mancanti in fase di compilazione.
- La forma dei dati documenta il dominio.
enum OrderStatus:
case Pending
case Shipped(tracking: String)
case Delivered(at: Long)
object Main:
def main(args: Array[String]): Unit =
val s: OrderStatus = OrderStatus.Shipped("TRK1")
println(s)Verifica rapida
Verifichi la sua comprensione della modellazione basata sugli ADT.
Riepilogo
Ha imparato a modellare il dominio con gli ADT.
- I tipi prodotto (
case class) combinano i campi con AND. - I tipi somma (
enum) offrono una scelta con OR. - Li annidi per modellare domini ricchi e strutture ricorsive.
- Usi
Optioninvece di null. - Progetti i tipi in modo che gli stati non validi non possano essere rappresentati.
enum Event:
case Created(id: Int)
case Deleted(id: Int, reason: String)
object Main:
def describe(e: Event): String = e match
case Event.Created(id) => s"created $id"
case Event.Deleted(id, reason) => s"deleted $id: $reason"
def main(args: Array[String]): Unit =
println(describe(Event.Deleted(1, "spam")))Domande Frequenti
La lezione «Modellazione con gli ADT» è gratuita?
Sì — il testo completo di «Modellazione con gli ADT» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Cosa imparerò in «Modellazione con gli ADT»?
Renda gli stati illegali non rappresentabili Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?
Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Modellazione con gli ADT»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?
Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Modellazione con gli ADT
- Costruttori intelligenti
- Newtype
- Composizione dei domini