3

什么是联合类型和交集类型?

我已经咨询过这个问题,但是一些小型工作类型系统会更好,而不是实用的系统。

具体来说,通过联合类型,我指的是这篇博文中提到 的类型,而不是 sum 类型,其中伪代码看起来像

{String, null} findName1() {
  if (...) {
    return "okay";
  } else {
    return null;
  }
}

维基百科页面对交集类型和联合类型有一个简短的解释,但似乎没有关于此的进一步参考。

4

3 回答 3

9

联合和交集类型只是将类型视为值集(主要是无限集)。如果这就是您对类型的看法,那么至少在概念上,可以将导致集合的集合上的任何操作应用于类型(值集)以创建新类型(值集)。

联合类型在某些意义上类似于您似乎熟悉的 sum 类型。事实上,我经常听到将 sum 类型描述为“有区别的联合”类型。基本区别在于,像(Haskell 表示法)这样的 sum 类型data FooBar = Foo Integer | Bar String允许您判断给定FooBar值是否包含 anInteger或 a String(因为FooBar值用Fooor标记Bar)。即使我们写data FooBar = Foo Integer | Bar Integer了两种类型相同的地方,“标签”也会添加额外的信息,我们可以知道FooBar值是“哪个整数”。

联合类型等价物类似于 (not valid Haskell) data FooBar = Integer | String。中的值FooBar只是所有字符串值和所有整数值。如果我们创建一个与它相同的两种类型的联合类型,data FooBar = Integer | Integer它应该在逻辑上与 just 没有区别Integer,因为集合与自身的联合就是它自己。

原则上,您可以对作为类型 A 和 B 的并集的类型 U 中的值做的事情只是对 As 和 Bs 起作用的操作;任何仅适用于 As 或 Bs 的操作都可能得到错误类型的输入,因为 U 没有信息来说明它是 A 还是B。1

(不加区别的)联合类型在具有类似于 Haskell 的类型系统的语言中不会很有趣,因为具体类型是不相交的2,所以唯一适用于 As 和 Bs 的操作适用于所有值(除非 A 是 B,其中它只是在该单一类型上工作的所有操作)。

但在某种程度上,类型类(如果你熟悉它们的话)是一种提供有点像联合类型的东西的方式。多态但被限制为某个类型类的成员的类型有点像类型类中所有类型的联合(除了你不知道它们是什么,因为类型类原则上是开放的); 您可以使用这样的值做的唯一事情是已声明对类型类中每种类型的值起作用的薄。

联合类型在具有子类型的语言中可能很有趣(这在面向对象的编程语言中很常见)。如果你将一个共同超类型的两个子类型联合在一起,你会得到至少支持超类型操作的东西,但它排除了超类型的任何其他子类型,所以它与仅使用超级类型。

交集类型正是这个概念,但使用交集而不是联合。这意味着您可以对类型 I 中的值(即类型 A 和 B 的交集)执行的操作是适用于 As的操作以及适用于 Bs 的操作;I 中的任何内容都保证既是 A 又是 B,因此可以安全地将其用于任何一种操作。

这些在具有类 Haskell 类型系统的语言中也不会很有趣。因为具体类型是不相交的2,所以任何非平凡的交​​集都是空的。但同样,类型类约束可以提供有点像交集类型的东西。如果您将多个类型类约束添加到同一个类型变量,则可以在预期该类型变量的地方使用的唯一值是所有类型类的“交集”中的类型,以及您可以使用的操作这些值是适用于任何类型类的操作。


1您可以想象将一个运算A -> C和一个运算组合起来B -> D得到一个运算(A | B) -> (C | D),就像您可以使用 sum 类型的标签将 sum 类型“路由”到适当的运算一样。但是对于完全通用的联合类型,它变得模糊不清。如果 A 和 B 重叠(并且一旦您获得联合类型,重叠类型就会进入竞争),那么您对重叠区域中的值调用哪个操作?如果你能分辨出它是 A 还是 B,那么你真的得到了 sum 类型而不是 union 类型,并且如果你应用一些任意的解析策略,比如选择A -> C操作,因为A前面在联合类型的定义中列出了,那么事情在简单的情况下工作正常,但如果你有像这样的类型(A | B) & (B | A)(我在哪里&表示交叉点)。

2尽管“不相交的类型”这一点值得商榷。在像data Maybe a = Nothing | Just a你这样的类型中,Nothing即使对于不同的a. 如果是这样,则 and 的Maybe String并集Maybe Integer只包含一个Nothing(而不是Nothing“无字符串”和Nothing“无整数”)。Maybe String而和的交集Maybe Integer只包含一个值,那就是Nothing

于 2013-07-18T00:07:16.413 回答
2

Whiley 编程语言支持联合和交集类型。如果您将类型视为集合(即类型int是所有有效整数的集合),则联合类型对应于集合并集,而交集类型对应于集合交集。

Whiley 中联合类型的经典示例是表示“可空”类型,如下所示:

null|int indexOf(string str, char c):
    for i in 0..|str|:
       if str[i] == c:
          return i // found a match
    // didn't find a match
    return null

在这里,类型null|int可以包含任何有效的整数或特殊null值。在 Whiley 中,您不能对这种类型执行算术运算。因此,您首先必须键入 test 以检查 null 值,然后才能使用返回的值。例如,像这样:

string replaceFirst(string str, char old, char new):
    idx = indexOf(str,old)
    if idx is int:
        str[idx] = new
    // return potentially updated string
    return str

我在这里这里的 Whiley 中写了一些关于联合类型的帖子。交集类型是相似的,尽管目前编译器不太支持。

于 2013-07-18T01:40:34.943 回答
1

一个类型可以看作是一组值。例如,如果Boolean是值的集合,true并且false说某个值具有类型Boolean意味着它要么是值,要么truefalse

请注意,某些类型,例如String,可以有无限多个可能的值。

您可能知道,并集和交集是集合操作,因此它们也适用于类型。例如,当有类型 T1 = {male, female} 和 T2 = {not-applicable} 时,可以构建类型 T3 = T1 \union T2 = {male, female, not-applicable}。这种类型有用的一个例子是对以下问题的回答:“你第一个出生的孩子的性别是什么?” 由于有些人没有孩子,他们可以回答:不适用。

于 2013-07-17T14:00:33.173 回答