Hay algunos problemas que se resuelven fácilmente con los tipos de datos algebraicos, por ejemplo, un tipo de lista puede expresarse de manera muy sucinta como:
data ConsList a = Empty | ConsCell a (ConsList a)
consmap f Empty = Empty
consmap f (ConsCell a b) = ConsCell (f a) (consmap f b)
l = ConsCell 1 (ConsCell 2 (ConsCell 3 Empty))
consmap (+1) l
Este ejemplo en particular está en Haskell, pero sería similar en otros idiomas con soporte nativo para tipos de datos algebraicos.
Resulta que hay una asignación obvia a los subtipos de estilo OO: el tipo de datos se convierte en una clase base abstracta y cada constructor de datos se convierte en una subclase concreta. Aquí hay un ejemplo en Scala:
sealed abstract class ConsList[+T] {
def map[U](f: T => U): ConsList[U]
}
object Empty extends ConsList[Nothing] {
override def map[U](f: Nothing => U) = this
}
final class ConsCell[T](first: T, rest: ConsList[T]) extends ConsList[T] {
override def map[U](f: T => U) = new ConsCell(f(first), rest.map(f))
}
val l = (new ConsCell(1, new ConsCell(2, new ConsCell(3, Empty)))
l.map(1+)
Lo único que se necesita más allá de las subclases ingenuas es una forma de sellar , es decir, una forma de hacer que sea imposible agregar subclases a una jerarquía.
¿Cómo abordaría este problema en un lenguaje como C # o Java? Los dos obstáculos que encontré al intentar usar los tipos de datos algebraicos en C # fueron:
- No pude averiguar cómo se llama el tipo de fondo en C # (es decir, no pude averiguar qué poner en
class Empty : ConsList< ??? >
) - No pude encontrar una manera de sellar
ConsList
para que no se puedan agregar subclases a la jerarquía
¿Cuál sería la forma más idiomática de implementar tipos de datos algebraicos en C # y / o Java? O, si no es posible, ¿cuál sería el reemplazo idiomático?