Skip to content

🔥代数数据类型(ADT):如何用 JS 模拟 Sum 与 Product 类型?

——Either(Sum)、Tuple(Product)的实现与模式匹配

“JavaScript 没有类型系统?
不,它只是把类型构造的权力,交给了程序员。”

一、什么是代数数据类型(Algebraic Data Types, ADT)?

ADT 是函数式语言(如 Haskell、ML)的核心类型系统,由两种基本构造组成:

类型数学类比含义
Sum TypeA + B“或”关系:值是 A B
Product TypeA × B“且”关系:值是 A B

它们被称为“代数”,因为其可能值的数量符合加法与乘法。

二、Product Type(乘积类型):A 且 B

核心:组合多个值

最典型的 Product Type 是 TupleRecord

实现 Tuple

js
const Tuple = (a, b) => ({
  a, b,
  map: f => Tuple(a, f(b)), // 通常映射第二个值
  toString: () => `(${a}, ${b})`
});

使用示例

js
const userWithAge = Tuple("Alice", 30);
// 类型:String × Number

一个 Tuple(String, Number) 有:

  • |String| × |Number| 种可能值(巨大乘积)

这就是“乘积”的由来。

Record(对象)也是 Product Type

{ name: "Alice", age: 30, active: true }
// 类型:String × Number × Boolean

三、Sum Type(和类型):A 或 B

核心:互斥的选择

最典型的 Sum Type 是 EitherMaybe

实现 Either(Left + Right)

js
const Left = value => ({
  value,
  map: () => Left(value),
  chain: () => Left(value),
  fold: (leftFn, rightFn) => leftFn(value),
  toString: () => `Left(${value})`
});

const Right = value => ({
  value,
  map: f => Right(f(value)),
  chain: f => f(value),
  fold: (leftFn, rightFn) => rightFn(value),
  toString: () => `Right(${value})`
});

const Either = { Left, Right };

使用示例

js
const result = Math.random() > 0.5 
  ? Either.Right(42) 
  : Either.Left("Error");

// 类型:Number + String

一个 Either(Number, String) 有:

  • |Number| + |String| 种可能值

这就是“和”的由来。

Maybe 是 Sum Type

js
const Maybe = {
  Just: value => ({ tag: 'Just', value }),
  Nothing: () => ({ tag: 'Nothing' })
};

// 类型:A + Unit(Nothing 是单值类型)

四、为什么叫“代数”?—— 类型的算术

类型即数字

  • Boolean:2 个值 → 大小为 2
  • Unit(如 null):1 个值 → 大小为 1
  • Void(无值):0 个值 → 大小为 0

构造规则

  • ProductA × B|A| × |B|
  • SumA + B|A| + |B|

示例:RGB 颜色

js
// Product Type
const Color = (r, g, b) => ({ r, g, b });
// 每个分量 0-255 → 256 值
// 总可能值:256 × 256 × 256 = 16,777,216

示例:结果类型

// Sum Type
type Result = Success Value | Failure Error
// |Result| = |Value| + |Error|

五、模式匹配:解构 ADT

ADT 的强大在于可预测的结构,适合模式匹配。

JavaScript 中的“模式匹配”实现

方法 1:fold(推荐)

js
const handleResult = result =>
  result.fold(
    error => console.error("Failed:", error),
    data => console.log("Success:", data)
  );

handleResult(Either.Right("ok"));  // Success: ok
handleResult(Either.Left("404"));  // Failed: 404

方法 2:tag 检查(TypeScript 风格)

js
const maybeValue = Maybe.Just(5);

if (maybeValue.tag === 'Just') {
  console.log(maybeValue.value * 2);
} else {
  console.log("No value");
}

方法 3:match 函数

js
const match = (adt, patterns) => adt.fold(patterns.Left, patterns.Right);

match(Either.Right(10), {
  Left: e => `Error: ${e}`,
  Right: x => `Value: ${x}`
}); // "Value: 10"

六、真实工程应用

1. API 响应建模

js
const Response = {
  Loading: () => ({ tag: 'Loading' }),
  Success: data => ({ tag: 'Success', data }),
  Error: msg => ({ tag: 'Error', msg })
};

// 在 React 中使用
const render = state =>
  state.tag === 'Loading' ? <Spinner />
  : state.tag === 'Success' ? <Data data={state.data} />
  : <Error msg={state.msg} />;

完美替代 isLoadingdataerror 三个分散状态。

2. 事件流(Redux Action)

text
const Action = {
  ADD: payload => ({ type: 'ADD', payload }),
  DELETE: id => ({ type: 'DELETE', id }),
  FETCH_START: () => ({ type: 'FETCH_START' }),
  FETCH_SUCCESS: data => ({ type: 'FETCH_SUCCESS', data })
};

// reducer 中模式匹配
switch(action.type) {
  case 'ADD': ...
  case 'DELETE': ...
}

七、TypeScript 中的 ADT(更安全)

ts
// Sum Type
type Result<T, E> = 
  | { success: true; value: T }
  | { success: false; error: E };

// Product Type
interface User {
  name: string;
  age: number;
}

// 使用
const handle = (result: Result<string, string>) => {
  if (result.success) {
    result.value.toUpperCase(); // 类型自动推断
  } else {
    console.error(result.error);
  }
};

八、为什么 ADT 重要?

清晰表达业务逻辑

  • “用户状态”是 LoggedIn | LoggedOut
  • “加载状态”是 Loading | Success | Error

编译时检查(TS)

  • 避免无效状态(如 loading: truedata: nullerror 存在)

可组合性

  • ADT + Functor + Applicative + Monad = 强大类型系统

结语:ADT 是“类型即设计”

它强迫你思考:这个值可能是什么?有哪些状态?

Either 不只是一个错误处理工具,
它是 Success + Failure 的代数表达。

Tuple 不只是两个值,
它是 A × B 的乘积构造。

在 JavaScript 这个“灵活”的语言中,
ADT 是你构建健壮、可维护系统的基石。