为什么我的类型定义在声明为变量时被拒绝为循环,但是否则接受?

时间:2015-10-03 20:22:10

标签: types functional-programming ocaml ml cyclic

我正在使用OCaml来实现Chris Okasaki的Purely Functional Data Structures中的一些数据结构,并且遇到了这种类型的定义:

 type tree = Node of int * int * tree list;;

我认为它不需要标签,因为它不是联合类型,所以我尝试删除标签,但是我收到了以下错误:

# type tree = int * int * tree list;;
Characters 5-33:
type tree = int * int * tree list;;
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The type abbreviation tree is cyclic

为什么两个看似相同的类型定义会发生这种情况?

2 个答案:

答案 0 :(得分:8)

在类似ML的语言中,递归类型的定义是递归不通过变体类型的定义。这是一个实用的定义,因为它往往会导致更有用的类型检查。

关于递归类型没有什么难以处理的。您可以使用-rectypes标志在OCaml中启用对递归类型的支持。

$ ocaml -rectypes
        OCaml version 4.02.1

# type tree = int * int * tree list;;
type tree = int * int * tree list
# let x: tree = (3, 3, [(4, 4, [])]);;
val x : tree = (3, 3, [(4, 4, [])])

启用递归类型时,会出现所有常见的强类型保证。主要缺点是许多非预期的程序被接受。换句话说,递归类型的存在通常表示编程错误。

答案 1 :(得分:1)

第一个类型定义定义了新类型。省略构造函数名称时,不是定义新类型,而是实际引入类型缩写。默认情况下,类型缩写不允许递归,因为通常这不是你的意思。

您可以使用定义新类型的任何类型定义语法来创建递归类型,而不仅仅是变体。记录也可以,例如

type tree = { node : int * int * tree list }

甚至更好

type tree = {
  value : int;
  depth : int;
  children : tree list;
}

(注意:字段名称是任意选择的,因为我不知道它们的最初目的)

总而言之,sum类型不仅用于引入不相交的类型集,还用于创建新类型,因此:

 type t = Constr x

引入了类型t,可以使用类型为Constr的值的构造函数x构建。