Los tipos de datos algebraicos son distintos porque pueden construirse a partir de varios tipos de "cosas". Por ejemplo, un árbol puede contener nada (vacío), una hoja o un nodo.
data Tree = Empty
| Leaf Int
| Node Tree Tree
Dado que un Nodo se compone de dos Árboles, los tipos de datos algebraicos pueden ser recursivos.
La coincidencia de patrones permite que los tipos de datos algebraicos se descompongan de una manera que mantenga la seguridad de tipos. Considere la siguiente implementación de profundidad y su pseudocódigo equivalente:
depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)
comparado con:
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)
Esto tiene la desventaja de que el programador debe recordar que se debe colocar Vacío antes de Hoja para que no se acceda a campo1 en un árbol Vacío. Del mismo modo, el caso Leaf se debe declarar antes del caso Node para que no se acceda a field2 en Leaf. Por lo tanto, el lenguaje no mantiene el tipo de seguridad, sino que impone una carga cognitiva adicional al programador. Por cierto, estoy captando estos ejemplos directamente de las páginas de wikipedia.
Por supuesto, un idioma que escribe pato podría hacer algo como esto:
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
Por lo tanto, los tipos de datos algebraicos pueden no ser estrictamente mejores que su equivalente de POO, pero proporcionan un conjunto diferente de tensiones con las que trabajar cuando se construye un software.