变体定义中的多态变体限制

时间:2018-11-10 02:56:12

标签: types ocaml polymorphic-variants

假设我想在OCaml中建模一个简单的表达式类型:

type expr = 
| `Int of int
| `Str of string
| `IntAdd of expr * expr
| `StrAdd of expr * expr

是否可以将expr中的expr * expr限制为expr本身的特定构造函数(即,我希望IntExpr仅允许使用'Int's)?我可以用模式模仿 匹配,但在expr扩展后变得麻烦。我能以某种方式 使用OCaml的类型系统来实现这一目标?

我尝试如下使用多态类型上限:

type expr = 
| `Int of int
| `Str of string
| `IntAdd of [< `Int] * [< `Int]
| `StrAdd of [< `Str] * [< `Str]

,但是编译器不接受(带有消息In case IntAdd of [< Int ] * ([< Int ] as 'a) the variable 'a is unbound)。有什么技巧可以使这项工作成功吗?

1 个答案:

答案 0 :(得分:2)

给出的示例足够简单,足以满足多态变体的需求:

type int_expr = [`Int of int | `Add of int_expr * int_expr]
type string_expr = [`String of string | `Concat of string_expr * string_expr]
type expr = [int_expr | string_expr]

如果您想要更多有趣的功能(例如多态数据结构),则必须使用GADT:

type _ expr =
  | Int : int -> int expr
  | Add : int expr * int expr -> int expr
  | String : string -> string expr
  | Concat : string expr * string expr -> string expr
  | Pair : 'a expr * 'b expr -> ('a * 'b) expr
  | Fst : ('a * 'b) expr -> 'a expr
  | Snd : ('a * 'b) expr -> 'b expr

GADT会影响错误消息的推论和可理解性,因此,如果您决定使用它们,则要做好克服这些困难的准备。