Алгебраические типы данных отличаются тем, что они могут быть построены из нескольких типов «вещей». Например, Дерево может не содержать ничего (Пусто), Лист или Узел.
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)
Это имеет недостаток, заключающийся в том, что программист должен помнить регистр Empty перед Leaf, чтобы поле field1 не было доступно для пустого дерева. Аналогично, регистр 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
Таким образом, алгебраические типы данных не могут быть строго лучше, чем их эквивалент ООП, но они предоставляют другой набор напряжений для работы при создании программного обеспечения.