
Haskell's algebraic data types我试图充分理解Haskell的所有概念。 代数数据类型在哪些方面类似于通用类型,例如在C#和Java中? 它们有什么不同? 无论如何,它们的代数是什么? 我熟悉通用代数及其环和域,但是对Haskell的类型如何工作只有一个模糊的想法。 Haskell的代数数据类型之所以这样命名,是因为它们与类别理论中的初始代数相对应,从而为我们提供了一些定律,一些运算和一些要操纵的符号。我们甚至可以使用代数符号来描述常规数据结构,其中:
带有一些附加的符号:
实际上,如果可以用 使用这种表示法,我们可以简明地描述许多常规数据结构:
还有其他操作(摘自参考文献中列出的Brent Yorgey的论文):
参考文献:
Haskell中的"代数数据类型"支持完整的参数多态性,这是泛型在技术上更正确的名称,作为简单的示例,列表数据类型为:
等效于(尽可能,忽略非严格评估等)
当然,Haskell的类型系统允许更多...有趣地使用类型参数,但这只是一个简单的示例。关于"代数类型"的名称,老实说,我从来没有完全确定将其命名的确切原因,但是假设它是由于类型系统的数学基础所致。我认为,其原因可以归结为ADT是"一组构造函数的产品"的理论定义,但是距我大学毕业已经过去了两年,所以我不再记得具体细节了。 [编辑:感谢克里斯·康威(Chris Conway)指出了我的愚蠢错误,ADT当然是求和类型,构造函数提供了字段的乘积/元组]
在通用代数中
例如,假设您有一种"列表元素"和
此时,有许多适合描述的代数,
没有这些不良性质的代数称为
名称的初始名称来自该属性,即确切地存在 对于多态类型,它变得更加复杂... 他们之所以称为代数的简单原因;有和(逻辑析取)和乘积(逻辑合取)两种类型。总和类型是有区别的联合,例如:
产品类型是具有多个参数的类型:
在O'Caml中,"产品"变得更加明确:
Haskell的数据类型由于与分类初始代数的联系而被称为"代数"。但这就是疯狂。 @olliej:ADT实际上是"求和"类型。元组是产品。 @Timbo: 您基本上是对的,就像一个抽象的Tree类,带有三个派生类(Empty,Leaf和Node),但是您还需要强制保证使用Tree类的某个人永远不会添加任何新的派生类,因为使用Tree数据类型的策略是编写基于树中每个元素的类型在运行时切换的代码(添加新的派生类型将破坏现有代码)。您可以想象一下在C#或C ++中这种讨厌的情况,但是在Haskell,ML和OCaml中,这对于语言设计和语法至关重要,因此编码样式可以通过模式匹配以更加方便的方式支持它。 ADT(和类型)也类似于C或C ++中的带标记的联合或变量类型。 这是一个古老的问题,但没有人提到可空性,这是代数数据类型的重要方面,也许是最重要的方面。由于每个值都是替代值之一,因此基于穷举案例的模式匹配是可能的。 对我来说,Haskell的代数数据类型的概念在C#之类的OO语言中总是看起来像多态。 请参阅http://en.wikipedia.org/wiki/Algebraic_data_types中的示例:
这可以在C#中作为TreeNode基类实现,具有派生的Leaf类和派生的TreeNodeWithChildren类,并且甚至需要派生的EmptyNode类。 (好的,我知道,没有人会这样做,但至少您可以这样做。) |