代数数据类型很容易解决一些问题,例如,列表类型可以非常简洁地表示为:
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
这个特定的例子在Haskell中,但是在其他语言中,本机支持代数数据类型,这将是相似的。
事实证明,有一个明显的面向对象样式子类型的映射:数据类型成为抽象基类,每个数据构造函数都成为具体的子类。这是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+)
天真的子类之外,唯一需要的是密封类的方法,即一种不可能将子类添加到层次结构的方法。
您将如何使用C#或Java这样的语言解决这个问题?我在C#中尝试使用代数数据类型时发现了两个绊脚石:
- 我不知道在C#中到底该调用什么类型(即我不知道要放入什么
class Empty : ConsList< ??? >
) - 我想不出一种密封 的方法,
ConsList
因此无法将任何子类添加到层次结构中
在C#和/或Java中实现代数数据类型的最惯用的方法是什么?或者,如果不可能的话,什么是惯用的替代品?