Алгебраїчні типи даних відрізняються тим, що їх можна побудувати з декількох типів "речей". Наприклад, Дерево не може містити нічого (порожнє), листя або вузол.
data Tree = Empty
| Leaf Int
| Node Tree Tree
Оскільки Вузол складається з двох Дерев, алгебраїчні типи даних можуть бути рекурсивними.
Відповідність шаблонів дозволяє деконструювати алгебраїчні типи даних таким чином, щоб підтримувати безпеку типу. Розглянемо таку реалізацію глибини та її еквівалент псевдокоду:
depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)
у порівнянні з:
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)
Це має той недолік, що програміст повинен пам’ятати, що він видав порожнє перед Leaf, щоб поле1 не було доступно до порожнього дерева. Аналогічно, випадок Leaf повинен бути оголошений перед випадком Node, щоб поле2 не було доступно до Leaf. Таким чином, безпека типу не підтримується мовою, а накладає додаткове пізнавальне навантаження на програміста. До речі, я захоплюю ці приклади безпосередньо зі сторінок вікіпедії.
Звичайно, мовник, що набирає качку, може зробити щось подібне:
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
Так що алгебраїчні типи даних можуть не бути суворо кращими, ніж їх еквівалент OOP, але вони створюють інший набір напруг, з якими можна працювати при створенні програмного забезпечення.