9

OCaml でインターフェイスをシミュレートしようとしていて、「type」構造を使用しています。私には2つのタイプがあります:

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

...そして、特定の fooSansBar を定義したい:

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

...しかし、バーフィールドが定義されていないと言われています。このことから、一致する fooSansBar の署名で渡された値とは対照的に、システムは私が fooConBar を作成しようとしていると認識しているようです。上記で定義された 2 つのタイプが存在する場合、fooSansBar を作成することは可能ですか?

さらに (私は OCaml が初めてなので) インターフェイスをシミュレートするためのより良い方法はありますか?

4

5 に答える 5

9

OCamlでは、レコードタイプのフィールド名は一意である必要があるため、定義する2つのタイプを同時に共存させることはできません。Camlは、このプロパティで私が知っている唯一の言語です。

2番目の定義は最初の定義を非表示にするため、コンパイラーはaフィールドとbフィールドを見ると、それらがタイプに属することを期待し、fooConBarバーフィールドがないことを訴えます。

インターフェイスをシミュレートしようとしている場合、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

モジュールとモジュールタイプを使用すると、サブタイピングも取得できます。オブジェクトに頼る必要はありません。

PSMyCamlはさびています。構文がオフになっている可能性があります。

于 2009-03-21T23:34:51.877 に答える
4

与えられたコードをどのように使用しているかに応じて、OCaml にはいくつかの可能な解決策があります。最も簡単なのは、2 つのタイプを組み合わせることです。

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)
于 2009-05-06T12:01:34.563 に答える
3

2 番目の型は a と b を再定義し、最初の型を効果的に隠します。これが、これ以上構築できない理由です。これらの型を別のモジュールで定義することもできますが、それは a と b に別の名前を使用するのと同じです。

これらのコンストラクトは、別のインターフェイスから「派生」しようとせず、単に実装する場合にのみ使用できます。

これらのオブジェクト指向の概念を Ocaml で使用したい場合は、オブジェクト システムを調べるか、問題によってはモジュール システムを調べることができます。または、機能的な方法で問題を解決することもできます。どのような問題を解決しようとしていますか?

于 2009-03-21T18:10:48.320 に答える
2

OCaml はインターフェイスを実装する 2 つの方法を提供します。1 つは、既に述べたように、モジュール タイプです。

もう 1 つはクラス型です。クラスタイプ(インターフェース)を書くことができますfooSansBar

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

およびクラス型 fooConBar:

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

fooConBarこれにより、 a が必要な場所ならどこでも aを使用できるようになりますfooSansBarfooSansBar型推論を使用して を作成できるようになりました。

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

現在、 Jon が示しているように、fsbの型はたまたま ですが、 OCaml の構造的なサブタイピングにより、<a: string; b: int>として完全に使用できます。fooSansBar

于 2010-11-23T22:32:00.773 に答える
1

OCaml では、交差するフィールド セットを持つ 2 つのレコード タイプを同じスコープに存在させることはできません。

交差するフィールド セットでレコード型を本当に使用する必要がある場合は、型を独自の専用モジュール内に囲むことで、この制限を回避できます。

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
于 2010-11-23T07:55:31.047 に答える