我正在尝试全面理解Haskell的所有概念。
代数数据类型与C#和Java中的泛型类型有哪些相似之处?它们又有何不同之处?它们究竟有什么代数意义呢?
我熟悉通用代数及其环和域,但对Haskell的类型如何工作只有一个模糊的概念。
我正在尝试全面理解Haskell的所有概念。
代数数据类型与C#和Java中的泛型类型有哪些相似之处?它们又有何不同之处?它们究竟有什么代数意义呢?
我熟悉通用代数及其环和域,但对Haskell的类型如何工作只有一个模糊的概念。
其他操作保持不变(参考Brent Yorgey在参考文献中列出的论文):
展开:展开fix point可以帮助我们思考列表。L = 1 + X + X² + X³ + ...
(即,列表要么为空,要么有一个元素、两个元素、三个元素等)。
组合:◦
给定类型F
和G
,组合 F ◦ G
是一种类型,用于构建“由G-结构构成的F-结构”(例如,R = X • (L ◦ R)
,其中L
是列表,是一棵玫瑰树)。
微分:数据类型D的导数(表示为D')是具有单个“孔”的D-结构的类型,即,不包含任何数据的显着位置。这令人惊奇地满足与微积分中的微分相同的规则:
1′ = 0
X′ = 1
(F + G)′ = F' + G′
(F • G)′ = F • G′ + F′ • G
(F ◦ G)′ = (F′ ◦ G) • G′
参考文献:
在Haskell中,“代数数据类型”支持完全的参数化多态性,这是泛型的更技术上正确的名称,以列表数据类型为简单示例:
data List a = Cons a (List a) | Nil
是等价的(尽可能地,并忽略非严格求值等)
class List<a> {
class Cons : List<a> {
a head;
List<a> tail;
}
class Nil : List<a> {}
}
当然,Haskell的类型系统允许更有趣的类型参数的使用,但这只是一个简单的例子。关于“代数类型”名称,我一直不太确定它们被命名的确切原因,但我认为这是由于类型系统的数学基础。我相信,ADT的理论定义是“一组构造函数的乘积”,这就是它们被命名为“代数类型”的原因,但是我已经毕业几年了,无法记起具体细节。data List a
是一个类型构造器,但 Cons 和 Nil 是数据构造器 - 它们表示类型为 List a 的值(这种区别很重要,因为它们存在于不同的命名空间中,所以你可以并且经常会有相同名称的类型和数据构造器)。 - Martin它们被称为代数类型的一个简单原因是,它们既有和(逻辑析取)类型,也有积(逻辑合取)类型。 求和类型是一种带标签的联合体,例如:
data Bool = False | True
一个产品类型是具有多个参数的类型:data Pair a b = Pair a b
在O'Caml中,“product”更加明确:
type 'a 'b pair = Pair of 'a * 'b
这是一个常见问题,但没有人提到可空性,这是一种代数数据类型中非常重要的方面,也许是最重要的方面。由于每个值都必须是其中的某个选择,因此可以进行详尽的基于情况的模式匹配。
对我来说,Haskell的代数数据类型的概念总是看起来像C#等面向对象语言中的多态。
看看http://en.wikipedia.org/wiki/Algebraic_data_types中的例子:
data Tree = Empty
| Leaf Int
| Node Tree Tree
这可以在C#中实现为一个TreeNode基类,带有一个派生的Leaf类和一个派生的TreeNodeWithChildren类,如果你想甚至还可以有一个派生的EmptyNode类。
(好吧,我知道,没有人会这样做,但至少你可以这样做。)