Types 为什么我的类型定义在声明为变量时被拒绝为循环,但在其他情况下被接受?

Types 为什么我的类型定义在声明为变量时被拒绝为循环,但在其他情况下被接受?,types,functional-programming,ocaml,ml,cyclic,Types,Functional Programming,Ocaml,Ml,Cyclic,我在使用OCaml实现Chris Okasaki的纯功能数据结构中的一些数据结构时遇到了这种类型定义: type tree = Node of int * int * tree list;; 我认为它不需要标记,因为它不是联合类型,所以我尝试删除该标记,但出现以下错误: # type tree = int * int * tree list;; Characters 5-33: type tree = int * int * tree list;; ^^^^^^^^^^^^^^

我在使用OCaml实现Chris Okasaki的纯功能数据结构中的一些数据结构时遇到了这种类型定义:

 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

为什么两个看似等价的类型定义会出现这种情况?

在类似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, [])])

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

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

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

type tree = { node : int * int * tree list }
甚至更好

type tree = {
  value : int;
  depth : int;
  children : tree list;
}
(注意:字段名是任意选择的,因为我不知道它们的原始用途)

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

 type t = Constr x

介绍了类型
t
,它可以用构造函数
Constr
从类型
x
的值构造,我对ocaml一无所知,但是如果没有
节点,所讨论的类型是否意味着“一个int、一个int和一棵树”,这意味着它的大小未知?在.NET(我效忠的框架)中,这将被称为“结构”。基本上,每棵树都是两个整数+一棵树,这棵树的大小是未知的,除非允许允许空指针的指针(或者在ocaml中调用的任何指针)?我的一个朋友刚刚告诉我,这是由于ML试图完全扩展第二棵树,而只键入第一棵树创建的检查值造成的。因为在第一种情况下,程序员有责任创建终止的值。问题不应该是:为什么我的类型定义在声明为变量时被接受,而在声明为变量时被拒绝?