Wpis na blogu, o którym wspomniałeś, dotyczy bardziej matematycznych aspektów typów danych algebraicznych, dotyczących ich praktycznego zastosowania w programowaniu. Myślę, że większość funkcjonalnych programistów nauczyła się najpierw o typach danych algebraicznych, używając ich w pewnym języku programowania, a dopiero później badała ich właściwości algebraiczne.
Rzeczywiście, intencją blogu jest jasne od samego początku:
w tej serii postów Wytłumaczę dlaczego typy danych Haskell są nazwie algebraicznych - bez wymieniania teorii kategorii lub zaawansowanych matematyka.
W każdym razie praktyczna użyteczność typów algebraicznych jest najlepiej doceniana podczas zabawy z nimi.
Załóżmy na przykład, że chcesz napisać funkcję przecinającą dwa segmenty na płaszczyźnie.
def intersect(s1: Segment, s2: Segment): ???
Jaki powinien być wynik? To kuszące, aby napisać:
def intersect(s1: Segment, s2: Segment): Point
, ale co, jeśli nie ma skrzyżowania? Można próbować załatać tę skrzynkę narożną zwracając null
lub rzucając wyjątek NoIntersection
. Jednak dwa segmenty mogą również nakładać się na więcej niż jeden punkt, gdy leżą na tej samej linii prostej. Co powinniśmy robić w takich przypadkach? Zgłaszanie innego wyjątku?
Podejście algebraiczne typy jest zaprojektowanie rodzaj obejmujący wszystkie przypadki:
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
Istnieje wiele praktycznych przypadków, gdy takie podejście czuje się zupełnie naturalne. W niektórych innych językach bez typów algebraicznych należy odwoływać się do wyjątków, do null
s (zobacz także the billion-dollar mistake), do klas niezamkniętych (uniemożliwiając kompilatorowi sprawdzenie kompletności dopasowywania wzorca) lub do innych funkcji przez język. Prawdopodobnie "najlepszą" opcją w OOP jest użycie Visitor pattern do kodowania typów algebraicznych i dopasowywania wzorców w językach, które nie mają takich funkcji.Mimo to posiadanie tego bezpośrednio wspieranego w języku, tak jak w scala, jest znacznie wygodniejsze.
Chcesz, aby krotki zwracały więcej niż jeden wynik, a chcesz, aby typy sumowały wybory, które wyraźnie zaznaczyłeś. (oczywiście jest to tylko pierwsza kropla w oceanie - możesz pisać książki o tych rzeczach). Link, który podałeś, może być mylący - możesz mieć pomysł, że potrzebujesz tych rzeczy tylko do wieżyczek z kości słoniowej-arkane-magii, ale jest to po prostu sposób na zarządzanie danymi w rozsądny sposób (szczególnie, jeśli nie masz klasy i odniesienia do dziedziczenia i mutacji do twojej dyspozycji) – Carsten
@Carsten Czuję, że rozumiesz, z czym jestem zdezorientowany. Doceniłem twój komentarz i mam nadzieję, że możesz powiedzieć coś więcej :) – Freewind
Wystarczy, że wyrazisz ostrzeżenie, że akronim "ADT" jest używany również w znaczeniu "Typ danych abstrakcyjnych", co jest przeciwieństwem pojęcia "Typ danych algebraicznych". Akronim "ADT" powinien zatem być używany z ostrożnością, tj. Wcale. – pigworker