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

时间:2009-03-21 17:45:32

标签: interface ocaml

我正在尝试模拟OCaml中的接口并使用“type”构造。我有两种类型:

type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;

...并且想要定义一个特定的fooSansBar:

let fsb = {a="a"; b=3};;

...但是我被告知没有定义条形字段。由此看来,与我在匹配fooSansBar签名时传递的值相反,系统认为我正在尝试创建一个fooConBar。如果存在上面定义的两种类型,是否可以创建一个fooSansBar?

另外(因为我是OCaml的新手)有更好的方法来模拟界面吗?

5 个答案:

答案 0 :(得分:9)

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

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

如果您正在尝试模拟界面,在Caml中执行此操作的正确方法是定义module type

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

使用模块和模块类型,您也可以获得子类型;没有必要求助于物体。

P.S。我的Caml生锈了;语法可能已关闭。

答案 1 :(得分:4)

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

type fooBar = { a: string; b: int; bar: char option }

另一个解决方案是用对象替换记录,因为对象支持子类型(并且可以推断出它们的类型,因此不需要声明类型!):

# let fsb = object
    method a = "a"
    method b = 3
  end;;
val fsb : < a : string; b : int > = <obj>

# fsb#a, fsb#b;;
- : string * int = ("a", 3)

答案 2 :(得分:3)

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

这些构造只能在您不尝试从其他接口“派生”时使用,而只是实现它。

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

答案 3 :(得分:2)

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

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

class type fooSansBar = object
    method a: string
    method b: int
end

和类类型fooConBar:

class type fooConBar = object
    inherit fooSansBar
    method bar: char
end

这样您就可以在需要fooConBar的任何地方使用fooSansBar。您现在可以使用类型推断创建fooSansBar

let fsb = object
    method a = "a"
    method b = 3
end

现在,fsb的类型恰好是<a: string; b: int>,如Jon所示,但由于OCaml的结构子类型,它完全可用作fooSansBar

答案 4 :(得分:1)

在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