0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

Algebraiczne typy danych

Modelowanie domeny

Algebraiczne typy danych to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Czym jest ADT?

Algebraiczny typ danych (ADT) to typ utworzony przez połączenie innych typów. W Scali modeluje się ADT za pomocą sealed trait oraz wariantów case class i case object.

ADT pozwalają precyzyjnie opisywać strukturę danych domeny.

Typy sum

Typ sum oznacza, że wartość jest jedną z kilku możliwości (LUB). Sygnalizator świetlny jest czerwony LUB żółty LUB zielony.

Wyraża się to za pomocą sealed trait i kilku wariantów.

sealed trait Light
case object Red extends Light
case object Yellow extends Light
case object Green extends Light
object Main {
  def main(args: Array[String]): Unit = {
    val l: Light = Yellow
    println(l)
  }
}

Typy iloczynowe

Typ iloczynowy oznacza, że wartość łączy kilka pól (ORAZ). Punkt ma współrzędną x ORAZ współrzędną y.

Case classes są typami iloczynowymi.

case class Point(x: Int, y: Int)
object Main {
  def main(args: Array[String]): Unit = {
    val p = Point(3, 4)
    println(s"${p.x} and ${p.y}")
  }
}

Łączenie typów sum i iloczynów

Rzeczywiste ADT łączą oba rodzaje: sealed trait (suma), którego wariantami są case classes (iloczyny).

W tym przypadku Shape to Circle (z promieniem) LUB Rectangle (z szerokością i wysokością).

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
  def main(args: Array[String]): Unit = {
    val s: Shape = Rectangle(3, 4)
    println(s)
  }
}

Operowanie na ADT

ADT przetwarza się przez dopasowywanie wzorców do jego wariantów. Każda gałąź obsługuje jeden kształt.

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
  def area(s: Shape): Double = s match {
    case Circle(r)       => 3.14159 * r * r
    case Rectangle(w, h) => w * h
  }
  def main(args: Array[String]): Unit = {
    println(area(Circle(2)))
    println(area(Rectangle(3, 4)))
  }
}

Modelowanie domeny

ADT sprawiają, że nieprawidłowych stanów nie da się reprezentować. Zamodeluj metodę płatności jako zamknięty zbiór prawidłowych opcji.

sealed trait PaymentMethod
case class CreditCard(number: String) extends PaymentMethod
case class BankTransfer(iban: String) extends PaymentMethod
case object Cash extends PaymentMethod
object Main {
  def main(args: Array[String]): Unit = {
    val m: PaymentMethod = Cash
    println(m)
  }
}

Rekurencyjne ADT

ADT może odwoływać się do samego siebie, co pozwala modelować drzewa i listy. Oto proste drzewo binarne.

sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
  def main(args: Array[String]): Unit = {
    val t: Tree = Node(1, Leaf, Node(2, Leaf, Leaf))
    println(t)
  }
}

Składanie rekurencyjnego ADT

Rekurencja wraz z dopasowywaniem pozwala przetwarzać całą strukturę. Tutaj sumujemy wszystkie wartości w drzewie.

sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
  def sum(t: Tree): Int = t match {
    case Leaf            => 0
    case Node(v, l, r)   => v + sum(l) + sum(r)
  }
  def main(args: Array[String]): Unit = {
    val t = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
    println(sum(t))
  }
}

Dlaczego ADT?

ADT są tak przydatne, ponieważ:

  • Precyzyjnie opisują dane jako sumy i iloczyny
  • Uniemożliwiają konstruowanie nieprawidłowych stanów
  • Doskonale współpracują z wyczerpującym dopasowywaniem wzorców
  • Skalują się do struktur rekurencyjnych, takich jak drzewa i listy

ADT a dziedziczenie

Tradycyjne OOP rozpraszałoby zachowanie pomiędzy podklasami. ADT utrzymują zamknięte definicje danych, a zachowanie umieszczają w funkcjach dopasowujących wzorce.

To rozdzielenie danych i zachowania jest cechą charakterystyczną projektowania funkcyjnego.

Połączenie wszystkiego

Kompletny, niewielki ADT z funkcją obsługującą każdy wariant.

sealed trait Json
case class JNum(n: Double) extends Json
case class JStr(s: String) extends Json
case object JNull extends Json
object Main {
  def render(j: Json): String = j match {
    case JNum(n) => n.toString
    case JStr(s) => "\"" + s + "\""
    case JNull   => "null"
  }
  def main(args: Array[String]): Unit = {
    List(JNum(3.0), JStr("hi"), JNull).foreach(j => println(render(j)))
  }
}

Szybkie sprawdzenie

Sprawdź, jak rozumiesz ADT.

Podsumowanie

Dowiedziałeś się, jak tworzyć algebraiczne typy danych:

  • Typy sum: sealed trait z wieloma wariantami (LUB)
  • Typy iloczynowe: case classes z polami (ORAZ)
  • Łącz je, aby precyzyjnie modelować domeny
  • ADT mogą być rekurencyjne (drzewa, listy)
  • Przetwarzaj je za pomocą dopasowywania wzorców

Często zadawane pytania

Czy lekcja „Algebraiczne typy danych” jest bezpłatna?

Tak — pełny tekst „Algebraiczne typy danych” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Co nauczysz się w „Algebraiczne typy danych”?

Modelowanie domeny Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?

Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Algebraiczne typy danych”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?

Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Klasy case
  2. Cechy sealed
  3. Algebraiczne typy danych
  4. Wyczerpujące dopasowywanie
← Powrót do Scala for Backend Engineering & Functional Programming