Interface 具有不同特异性水平的OCaml类型

Interface 具有不同特异性水平的OCaml类型,interface,ocaml,Interface,Ocaml,我试图在OCaml中模拟一个接口,并使用“类型”构造。我有两种类型: type fooSansBar = {a: string; b: int};; type fooConBar = {a:string; b:int; bar:char};; type fooBar = { a: string; b: int; bar: char option } …并希望定义一个特定的fooSansBar: let fsb = {a="a"; b=3};; …但我被告知条形字段未定义。由此看来,与我在匹

我试图在OCaml中模拟一个接口,并使用“类型”构造。我有两种类型:

type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;
type fooBar = { a: string; b: int; bar: char option }
…并希望定义一个特定的fooSansBar:

let fsb = {a="a"; b=3};;
…但我被告知条形字段未定义。由此看来,与我在匹配fooSansBar签名时传递的值相反,系统认为我正在尝试创建一个fooConBar。如果存在上面定义的两种类型,是否可以创建fooSansBar


另外(因为我是OCaml新手),有没有更好的方法来模拟接口?

第二种类型重新定义了a和b,有效地隐藏了第一种类型,这就是为什么不能再构造它的原因。您可以在不同的模块中定义这些类型,但这与为a和b使用不同的名称相同

只有当您不尝试从另一个接口“派生”而只是实现它时,才能使用这些构造


如果希望在Ocaml中使用这些面向对象的概念,可以查看对象系统,或者根据您的问题,查看模块系统。或者,您可以尝试以功能性的方式解决您的问题。您试图解决什么问题?

在OCaml中,记录类型中的字段名必须是唯一的,因此您定义的两种类型不能同时共存。Caml是我所知道的唯一一种具有此属性的语言

因为第二个定义隐藏了第一个定义,所以当编译器看到a和b字段时,它希望它们属于
fooConBar
类型,因此抱怨缺少bar字段

如果您试图模拟一个接口,在Caml中正确的功能方法是定义一个
模块类型

module type FOO_CON_BAR = sig
  val a : string
  val b : int
  val bar : char
end
还有一个例子:

module Example = struct
  let a = "hello"
  let b = 99
  let c = '\n'
end
使用模块和模块类型,您还可以获得子类型;没有必要求助于物体


另外,我的凸轮生锈了;语法可能已关闭。

OCaml中有几种可能的解决方案,具体取决于您如何使用提供的代码。最简单的方法是将两种类型结合起来:

type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;
type fooBar = { a: string; b: int; bar: char option }
另一种解决方案是用对象替换记录,因为对象支持子类型(并且可以推断其类型,因此无需声明类型!):

#让fsb=object
方法a=“a”
方法b=3
完;;;
val fsb:=
#金融稳定委员会a,金融稳定委员会b;;
-:string*int=(“a”,3)

在OCaml中,不可能在同一范围内存在两种具有相交字段集的记录类型

如果确实需要将记录类型与相交字段集一起使用,则可以通过将这些类型包含在它们自己的专用模块中来绕过此限制:

module FooSansBar = struct type t = {a:string; b:int} end
module FooConBar = struct type t = {a:string; b:int; bar:char} end
然后可以像这样构造这些类型的实例:

let fsb = {FooSansBar.a="a"; b=3}
let fcb = {FooConBar.a="a"; b=4; bar='c'}
这些实例具有以下类型:

fsb : FooSansBar.t 
fcb : FooConBar.t

OCaml提供了两种实现接口的方法。如前所述,其中之一是模块类型

另一个是类类型。您可以编写类类型(接口)
fooSansBar

class type fooSansBar = object
    method a: string
    method b: int
end
和类类型fooConBar:

class type fooConBar = object
    inherit fooSansBar
    method bar: char
end
这将允许您在需要
foosanBar
的任何位置使用
foosanBar
。现在可以使用类型推断创建
fooSansBar

let fsb = object
    method a = "a"
    method b = 3
end
现在,
fsb
的类型恰好是Jon指出的
,但由于OCaml的结构子类型,它完全可以用作
fooSansBar