Skip to content

使用代数数据类型

元语 提供 (定义结构) 定义单构造器类型,(定义枚举) 定义多构造器类型。

起初的思路 ​

假设我们要建模一个用户:一个编号,可能有邮箱,可能有电话。 (假设类型 邮箱地址型 和 电话号码型 已在别处定义。)

meta-lisp
(定义结构 用户型
  (编号 整数型)
  (邮箱 (或有型 邮箱地址型))
  (电话 (或有型 电话号码型)))

这样可行,但类型允许了一个领域所禁止的状态:既没有邮箱也没有电话的用户。

更好:把情况编码进类型 ​

用户必须至少有一种联系方式。恰好有三种情况:只有邮箱、只有电话、两者都有。

meta-lisp
(定义结构 用户型
  (编号 整数型)
  (联系方式 用户联系方式型))

(定义枚举 用户联系方式型
  (邮箱联系 (地址 邮箱地址型))
  (电话联系 (号码 电话号码型))
  (邮电联系 (地址 邮箱地址型) (号码 电话号码型)))

非法状态消失了:不可能构造出一个没有联系方式的用户。

新的需求 ​

现在我们需要系统用户,他们没有邮箱和电话。

一个诱人的改法:加上一个 (或有型 用户联系方式型) 字段和一个"为系统用户"标志。

meta-lisp
(定义结构 用户型
  (编号 整数型)
  (联系方式 (或有型 用户联系方式型))
  (为系统用户 真假型))

两个字段组合出四种状态,其中一种是非法状态:不是系统用户却没有联系方式。类型系统无法阻止它。

更好:添加一个构造器 ​

这个新需求不是一个新字段——而是用户联系方式的一个新情况。

meta-lisp
(定义结构 用户型
  (编号 整数型)
  (联系方式 用户联系方式型))

(定义枚举 用户联系方式型
  (系统联系)
  (邮箱联系 (地址 邮箱地址型))
  (电话联系 (号码 电话号码型))
  (邮电联系 (地址 邮箱地址型) (号码 电话号码型)))

改动是局部的:用户型 一行未动。四种状态全部合法,全部被表示。