使用稍后在OCaml的类型定义中声明的类型

Cod*_*bda 2 ocaml types

我目前正在OCaml中构建程序,并且遇到以下问题:我需要两种类型,这些类型包含另一种类型的值。它基本上是这样的(但稍微复杂一点):

type a = {
  x: some_other_type;
  next: b
};;

type b =
    NoA
  | SomeA of a;;
Run Code Online (Sandbox Code Playgroud)

我注意到我可以引用以前未定义的类型(因此此声明不会引发任何错误),但是如果我尝试使用它,它将区分b的两种类型:在a的定义中提到的一种,以及我定义的一个

我知道我可以用丑陋的方式做到这一点:

type 'b a = {
  x: some_other_type;
  next: 'b
};;

type b =
    NoA
  | SomeA of b a;;
Run Code Online (Sandbox Code Playgroud)

但是我想知道是否有更好的解决方案(尽管我不得不承认我很喜欢直接能够看到b是递归类型)。

ivg*_*ivg 5

首先,您的假设是错误的,您可以引用未定义的类型,例如,

# type a = {
  x: some_other_type;
  next: b
};;
      Characters 16-31:
    x: some_other_type;
       ^^^^^^^^^^^^^^^
Error: Unbound type constructor some_other_type
Run Code Online (Sandbox Code Playgroud)

因此,您some_other_type已定义。可能您是在一段时间之前在顶级会话中定义它的,而忘记了它。如果我定义some_other_type,那么我会得到一个Unbound type constructor b错误。因此,b和和some_other_type都是先前定义的。每次定义新类型(而不是别名)时,都会为您创建一个新的新类型构造函数,因此type a = A;; type a = A定义了两个不同(不兼容)的类型。实际上,您只能在交互式顶层中定义两个具有相同名称的类型(否则,如果您决定更改类型定义,则需要重新启动顶层)。OCaml编译器不允许您在同一结构中定义两个具有相同名称的类型。

要解决您的问题,您可以使用递归类型,

type some_other_type

type a = {
  x: some_other_type;
  next: b
}

and b =
    NoA
  | SomeA of a;;
Run Code Online (Sandbox Code Playgroud)

或者,也可以通过使多种类型之一成为多态来打破依赖性,例如,

type some_other_type

type 'b a = {
  x: some_other_type;
  next: 'b
}

type b =
    NoA
  | SomeA of b a;;
Run Code Online (Sandbox Code Playgroud)

要么

type some_other_type

type 'a b =
    NoA
  | SomeA of 'a

type a = {
  x: some_other_type;
  next: a b
}
Run Code Online (Sandbox Code Playgroud)