Algebraische Datentypen unterscheiden sich darin, dass sie aus mehreren Arten von "Dingen" erstellt werden können. Beispielsweise kann ein Baum entweder nichts (Leer), ein Blatt oder einen Knoten enthalten.
data Tree = Empty
| Leaf Int
| Node Tree Tree
Da ein Knoten aus zwei Bäumen besteht, können algebraische Datentypen rekursiv sein.
Mit Pattern Matching können algebraische Datentypen so dekonstruiert werden , dass die Typensicherheit erhalten bleibt. Betrachten Sie die folgende Implementierung der Tiefe und ihres Pseudocode-Äquivalents:
depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)
verglichen mit:
switch on (data.constructor)
case Empty:
return 0
case Leaf:
return 1
case Node:
let l = data.field1
let r = data.field2
return 1 + max (depth l) (depth r)
Dies hat den Nachteil, dass der Programmierer daran denken muss, Leer vor Blatt zu schreiben, damit auf Feld1 in einem leeren Baum nicht zugegriffen wird. Ebenso muss der Blattfall vor dem Knotenfall deklariert werden, damit auf Feld2 in Blatt nicht zugegriffen wird. Somit wird die Typensicherheit nicht durch die Sprache aufrechterhalten, sondern erlegt dem Programmierer eine zusätzliche kognitive Belastung auf. Übrigens greife ich diese Beispiele direkt von den Wikipedia-Seiten.
Natürlich könnte eine Sprache, die Enten tippt, so etwas tun:
class Empty
def depth
0
end
end
class Leaf
def depth
1
end
end
class Node
attr_accessor :field1, :field2
def depth
1 + [field1.depth, field2.depth].max
end
end
Daher sind algebraische Datentypen möglicherweise nicht unbedingt besser als ihre OOP-Entsprechung, bieten jedoch eine andere Menge von Spannungen, mit denen beim Erstellen von Software gearbeitet werden kann.