¿Cuáles son los usos de los tipos de datos algebraicos?


16

Estoy leyendo sobre tipos de datos algebraicos (gracias a Richard Minerich encontré esta excelente explicación del concepto). Si bien creo que entiendo la noción de tipos de suma y tipos de productos, etc., lo que no entiendo es cómo los tipos de datos algebraicos son útiles más allá de especificar la coincidencia de patrones. ¿Qué otras cosas se pueden hacer con ADT más allá de la coincidencia de patrones?


EDITAR: No estoy preguntando qué puede hacer un desarrollador con ADT que no se puede hacer con objetos. Estoy preguntando si hay otras operaciones que permiten ADT; por ejemplo, ¿se puede hacer un razonamiento adicional sobre los tipos involucrados si se emplean ADT? ¿Los ADT facilitan algún tipo de análisis de tipo que no sería posible sin ellos?


2
¿Qué se puede hacer con los objetos, excepto los métodos de llamada?

1
ADT en realidad se refiere al "tipo de datos abstractos", no a los tipos de datos algebraicos .
Rein Henrichs

44
@Rein: se puede referir a cualquiera de ellos según el contexto.
sepp2k

44
@Rein: De hecho (lo cual es bastante sorprendente para ser sincero): sin embargo, el artículo de Wikipedia para ADT enumera tanto el tipo de datos abstractos como el tipo de datos algebraicos como posibles significados. Y ADT se usa muy comúnmente como una abreviatura para tipos de datos algebraicos en, por ejemplo, la lista de correo de Haskell y el canal IRC.
sepp2k

1
@Rein, lo sé, simplemente me cansé de escribir "Tipo de datos algebraicos" una y otra vez y pensé que la gente podría entender a qué me refería dado el contexto.
Onorio Catenacci

Respuestas:


10

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

Como un nodo está compuesto por dos árboles, los tipos de datos algebraicos pueden ser recursivos.

La coincidencia de patrones permite que los tipos de datos algebraicos se deconstruyan de una manera que mantenga la seguridad de los tipos. Considere la siguiente implementación de profundidad y su equivalente de pseudocódigo:

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 acordarse de vaciar antes que Leaf para que no se acceda al campo 1 en un árbol vacío. Del mismo modo, el caso Leaf debe declararse antes del caso Node para que no se acceda al campo2 en Leaf. Por lo tanto, la seguridad de tipo no es mantenida por el lenguaje, sino que impone una carga cognitiva adicional en el programador. Por cierto, estoy tomando estos ejemplos directamente de las páginas de wikipedia.

Por supuesto, un lenguaje de escritura de 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 OOP, pero proporcionan un conjunto diferente de tensiones para trabajar al construir software.


9

No estoy tan seguro de que la explicación sea tan excelente.

Los tipos de datos algebraicos se utilizan para crear estructuras de datos, como listas y árboles.

Por ejemplo, los árboles de análisis se representan fácilmente con estructuras de datos algebraicos.

data BinOperator = Add
                 | Subtr
                 | Div
                 | Mult
                 | Mod
                 | Eq
                 | NotEq
                 | GreaterThan
                 | LogicAnd
                 | LogicOr
                 | BitAnd
                 | BitOr
                 | ...

data UnOperator = Negate
                | Not
                | Increment
                | Decrement
                | Complement
                | Ref
                | DeRef


data Expression = Empty
                | IntConst Int
                | FloatConst Float
                | StringConst String
                | Ident String
                | BinOp BinOperator Expression Expression
                | UnOp UnOperator Expression Bool //prefix or not
                | If Expression Expression Expression
                | While Expression Expression Bool //while vs. do while
                | Block List<Expression>
                | Call Expression List<Expression>
                | ...

En realidad, no tomaría mucho más representar el lenguaje C.

Pero realmente, puedes hacer TODO con tipos de datos algebraicos. Lisp demuestra que puede hacer todo con pares y ADT, simplemente proporciona una forma más granular y segura de este enfoque.

Por supuesto, si pregunta: "¿Qué puede hacer con los ADT, que no puede hacer con los objetos?", La respuesta es "nada". Solo a veces (en su mayoría) encontrará que las soluciones en ADT son significativamente menos detalladas, mientras que las basadas en objetos son posiblemente más flexibles. Entonces, para ponerlo en un árbol de análisis representado con ADT:

If(Call(Ident('likes_ADTs'),[Ident('you')]),
   Call(Ident('use_ADTs'),[Ident('you')]),
   Call(Ident('use_no_ADTs'),[Ident('you')]))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.