6

这两个概念都允许创建新的数据类型。我能看到的唯一区别是,在函数式语言中,可以对代数数据类型执行模式匹配。但是 OO 语言没有类似的简洁特性。这是一个准确的说法吗?

4

5 回答 5

6

代数数据类型之所以如此命名,是因为它们形成了“初始代数”,

+ represents sum types (disjoint unions, e.g. Either).
• represents product types (e.g. structs or tuples)
X for the singleton type (e.g. data X a = X a)
1 for the unit type ()
and μ for the least fixed point (e.g. recursive types), usually implicit.

从这些运算符可以构造所有常规数据类型。代数数据类型还支持参数多态性——这意味着它们可以用作任何底层类型的容器,并具有静态的安全保证。此外,ADT 提供了用于引入和消除数据类型的统一语法(通过构造函数和模式匹配)。例如

-- this defines a tree
data Tree a = Empty | Node a (Tree a) (Tree a)

-- this constructs a tree
let x = Node 1 (Node 2 Empty) Empty

-- this deconstructs a tree
f (Node a l r) = a + (f l) + (f r)

代数数据类型的丰富性和统一性,以及它们不可变的事实,将它们与 OO 对象区分开来,后者主要是:

  • 仅代表产品类型(因此没有递归或求和类型)
  • 不支持模式匹配
  • 是可变的
  • 不支持参数多态
于 2012-05-09T13:49:01.323 回答
5

我可以看到代数数据类型和 OO 样式类之间的三个主要区别,不包括(im)可变性,因为它会有所不同。

  • 代数数据类型允许求和以及乘积,而 OO 风格的类只允许乘积。
  • OO 风格的类允许您将复杂数据项与其可接受的操作捆绑在一起,而代数数据类型则不允许。
  • 代数数据类型不区分传递给构造函数的数据和存储在结果值中的数据,而 OO 风格的类可以(或可以)。

我故意从该列表中遗漏的一件事是子类型化。虽然绝大多数 OO 语言允许您对(非最终、非密封、当前可访问)类进行子类化,而绝大多数一般 ML 系列函数式语言不允许,但显然可以在假设的情况下完全禁止继承OO(或至少类 OO)语言,同样可以在代数数据类型中产生子类型和超类型;有关后者的有限示例,请参阅O'Haskell 上的此页面,该页面已由Timber接替

于 2012-05-09T06:39:08.857 回答
2

类不仅仅是一个类型定义——大多数 OO 语言中的类实际上是提供各种松散相关功能的厨房水槽功能。

特别是,类充当一种模块,为您提供数据抽象和命名空间。代数数据类型没有内置此功能,模块化通常作为单独的正交功能(通常是模块)提供。

于 2012-05-09T07:58:41.470 回答
2

从某种意义上说,人们可以这样看。每种语言只有这么多的机制来创建用户定义的类型。在函数式(ML,Haskell 风格)语言中,唯一的一个就是创建 ADT。(Haskell 的 newtype 可以看作是 ADT 的退化案例)。在 OO 语言中,它是类。在过程语言中它是structor record

不言而喻,用户定义数据类型的语义因语言而异,而且从范式#1 中的语言到范式#2 中的语言更是如此。@Pharien's Flame 已经概述了典型的差异。

于 2012-05-09T08:07:36.647 回答
0

代数数据类型的概念是否类似于 OO 语言中的类定义?

在函数式语言中,可以对代数数据类型执行模式匹配。但是 OO 语言没有类似的简洁特性。这是一个准确的说法吗?

这是其中的一部分。

正如 Andreas 所说,类是从 Simula 派生的静态类型的面向对象语言(如 C++、Java 和 C#)中的厨房水槽功能。类是万事通,但在这方面没有任何特征:它们解决了许多问题。

将 vanilla ML 和 Haskell 与 C++、Java 和 C# 中的 OO 进行比较,您会发现:

  1. 类可以包含其他类,而代数数据类型可以相互引用,但不能包含彼此的定义。
  2. 类层次结构可以任意深,而代数数据类型只有一级深:类型包含其类型构造函数,仅此而已。
  3. 新类可以从旧类派生,因此类是可扩展类型,而代数数据类型通常(但不总是)是封闭的。

所以 ADT 并不真正“类似于”类,因为它们只解决一个特定问题:深一层的类层次结构。从这个意义上说,我们可以看到两个近似的观察结果:

  1. ADT 需要组合而不是继承。
  2. 类使扩展类型变得容易,但很难扩展成员函数集,而 ADT 使扩展类型上的函数变得容易,但很难扩展类型。

您还可以查看 GoF 设计模式。它们已经使用 C++ 中的类来表达。功能等价物并不总是 ADT,而是诸如 lambda 函数而不是命令模式和高阶函数(如mapandfold而不是访问者模式等)。

于 2018-09-25T23:28:47.730 回答