美文网首页Theory
[PLT] product / sum / union / in

[PLT] product / sum / union / in

作者: 何幻 | 来源:发表于2018-06-06 15:33 被阅读17次

1. 积类型

在类型理论中,类型的(product)是一个复合类型(compounded type),
运算的操作数是类型(type),并且与操作数的顺序有关,
类型 A 和类型 B 的积类型,通常记为 A × B

一个具有积类型的表达式,通常被称为元组(tuple),
类型有时也被称为元组类型

以下为Haskell中的元组示例,

-- Haskell Code

(True, 1) :: Num t => (Bool, t)
("Hello world", False) :: ([Char], Bool)
(4, 5, "Six", True, 'b') :: (Num t1, Num t2) => (t1, t2, [Char], Bool, Char)

2. 和类型

和类型(sum type),又称为标签联合(tagged union),也是一种复合类型,
可看做是把不同的类型,通过携带标签(tag field)的方式的放在了一起。

类型 A 和类型 B 的和类型,通常记为 A + B

-- Haskell Code

data Bool = False | True    
data Maybe a = Just a | Nothing

其中,值构造器就可以看做标签(tag field)。

处理和类型的值,可以使用模式匹配,

-- Haskell Code

f :: Maybe Int -> Int 
f x = case x of
    Just i -> i
    Nothing -> 0

3. 联合类型

联合类型(union type)的值,是类型值集的并集

例如,在C语言中,signed char的取值范围是-128 ~ 127
unsigned char取值范围是0 ~ 255
则这两个类型的联合类型,取值范围就是-128 ~ 255

C语言中的联合类型不是类型安全的(not typesafe),
因为任何一个类型中的操作(operation),都可以用于联合类型,
这样如果当前值不属于那个类型时,就会出错。

下面我们来看TypeScript中的联合类型,它的类型安全的(typesafe),
TypeScript中的联合类型记为,A | B

// TypeScript Code

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // ...
}

let pet = getSmallPet();
pet.layEggs(); // okay
pet.swim();    // errors

以上TypeScript代码中,getSmallPet返回值的类型是一个联合类型Fish | Bird
则表明,或者类型为Fish,或者类型为Bird

TypeScript只允许调用FishBird都有的方法,例如,layEggs
这样做是类型安全的。

4. 交叉类型

交叉类型(intersection type)的值,是类型值集的交集

例如,在C语言中,signed char的取值范围是-128 ~ 127
unsigned char取值范围是0 ~ 255
则它们的交叉类型,取值范围是0 ~ 127

对于交叉类型的值,可以安全的进行每个类型上可以进行的操作,
因为它属于所有的类型。

Flow.js中的交叉类型记为,A & B

// @flow
type A = { a: number };
type B = { b: boolean };
type C = { c: string };

function method(value: A & B & C) {
  // ...
}

// $ExpectError
method({ a: 1 }); // Error!
// $ExpectError
method({ a: 1, b: true }); // Error!
method({ a: 1, b: true, c: 'three' }); // Works!

注:
(1)对联合类型来说,值集是参与联合的类型的值集之并,
但值集上类型安全的操作是交集。

对于交叉类型来说,值集是参与交叉的类型的值集之交,
但是值集上类型安全的操作是并集。

从值集的角度进行说明,其实不够严谨,应该从类型推导规则的角度来看。
这里只是不严谨的理解一下。

(2)交叉类型和联合类型是对偶概念(dual)。
例如,交叉类型经常用于描述重载函数(overloaded function)的类型,

/* @flow */
class Foo {}
class Bar {}
declare var f: ((x: Foo) => void) & ((x: Bar) => void);
f(new Foo());
f(true); // Flow will error here.

TypeScript有两种方式来描述,

interface A {
  (t: number): void;
  (t: string): void;
}
var func: A
// in TypeScript 1.4

interface A {
  (t: number | string): void;
}
var func: A

这两种描述是等价的,

(t: number | string): void
(t: number) => void & (t: string) => void

TypeScript 1.6已增加了交叉类型。


参考

Algebraic data type

Sum type
tagged union

Product type
Haskell: tuple

Union types
Union type
TypeScript: union types

Intersection types
Thoughts on Intersection Types
Flow: intersection types

Null-tracking, or the difference between union and sum types

相关文章

网友评论

    本文标题:[PLT] product / sum / union / in

    本文链接:https://www.haomeiwen.com/subject/basbsftx.html