2012-03-19 6 views
12

OCaml(3.12.1)のモジュール言語を実験しています。モジュールのファンクタとシグネチャを定義しています。ほとんどの例はChapter 2 of the OCaml manualです。私は偶然、つまずきました。明らかに、ファンクターとモジュール署名がどのように機能するかに関する私の精神的モデルには欠陥があります。最短のコードで遭遇した状況を絞り込もうとしました。私が達成しようとしていることを尋ねないでください。これは問題のOCaml機能を実証するための完全に考案された例です。OCaml functors :: counter直感的な振る舞い

そこで、我々は単に恒等関数「F」を提供し、その関数の入力パラメータの種類を供給モジュールによってパラメータ化されたファンクタを持っています。私が言ったような完全に考案された例。

上記の
module type SOMETYPE = sig type t end ;; 
module Identity = functor (Type: SOMETYPE) -> struct let f (x: Type.t) = x end ;; 

、我々はint型を供給するためのモジュールを定義するために進ん:

module IntType = struct type t = int end ;; 

を...し、その後、我々はint型のアイデンティティ機能のためのモジュールを生成するためにファンクタを使用します。

期待どおりに動作し、十分な
module IdentityInt = Identity(IntType) ;;      

確か生成モジュールとそのf関数:

#IdentityInt.f(3) + 10 ;; 
- : int = 13 

ファンクタのメンタルモデルは、モジュールを入力およびリターンモジュールとして使用する関数であり、これまでのところ私たちに役立っているようです。 Identityファンクタは、入力パラメータとして署名(モジュール型)SOMETYPEのモジュールを想定し、実際に我々は供給モジュール(IntType)は、そのf関数期待通りに振る舞う正しい署名を有するので、有効な出力モジュールが製造される(IdentityInt)。

今直感的ではない部分があります。提供されたモジュールIntTypeが確かにSOMETYPEタイプのモジュールであることを明示したい場合はどうでしょうか?その後、

module IntType : SOMETYPE = struct type t = int end ;; 

とファンクタの出力モジュールは、前と同じように生成します:同様に

module IdentityInt = Identity(IntType) ;; 

...のは、新しく生成されたモジュールのf機能を使用してみましょう:

IdentityInt.f 0 ;; 

この場合、REPLは次のように文句を言います。

"Error: This expression [the value 0] has type int but an expression was expected of type IntType.t." 

重複しているが正しいタイプの情報を提供すると、コードが破損することはありますか?ケースAの場合でも、ファンクタモジュールIDはIntTypeモジュールをSOMETYPEタイプとして扱わなければならなかった。では、IntTypeSOMETYPE型に明示的に宣言すると、どのように異なる結果が得られますか?

+0

2番目の 'module IntType'に' = int'部分がありませんか? – Ptival

+0

いいえ、私のREPLのコピー貼り付けフォームのタイプミスです。 2番目のモジュールIntTypeは正しく読み込まれます: 'module IntType:SOMETYPE = struct type t = int end'そして、上で説明したのとまったく同じ結果を得ます。私はあまりにも誤解を避けるために投稿を編集します。 –

答えて

10

:構造体は、コア言語とモジュール言語が異なります。コア言語では、注釈構造です。たとえば、((3, x) : 'a * 'a list)は、式が'a * 'a listのインスタンスである型を持つように制約します。ペアの最初の要素は整数なので、let (a, b) = ((3, x) : 'a * 'a list) in a + 1の型が整っています。モジュール上の:構成は、これを意味するものではありません。

構築M : Sシール署名SにモジュールM。これは不透明なシールです。M : Sのタイプを入力するときには、署名Sに記載されている情報のみが利用可能です。タイプIntTypeは、この定義によって生成された、新しいタイプです:あなたはmodule IntType : SOMETYPE = struct type t endを書くとき、これはタイプフィールドので

module IntType = (struct type t end : SOMETYPE) 

ためSOMETYPEt代替構文であることIntTypeは抽象型フィールドtがあり、未指定のままにされます。

ところで、おそらくmodule IntType = (struct type t = int end : SOMETYPE)を意味します。いずれにせよ、IntType.tは抽象型です。

モジュールに特定のシグネチャがあるように指定し、一部のタイプを公開したい場合は、これらの型に明示的に等価を追加する必要があります。モジュールにシグネチャを適用するのは、通常、情報を隠すためのものであるため、すべての推測可能な等価を追加する構造はありません。単純化のために、この言語はこの生成的な密封構造を提供するだけです。あなたが定義された署名SOMETYPEを使用し、タイプtの透明性を保持したい場合は、署名に制約を追加します。

module IntType = (struct type t = int end : SOMETYPE with type t = int) 
+0

うん、その 'モジュールIntType =(構造体タイプt = int終わり:SOMETYPE)'私は意味しました。私のREPLからのコピーミスでした(私はそれを修正するために投稿を編集しました)。それでも、あなたが言うように、人は同じ結果を得ます。私は今モジュールの ':'構造をアノテーションではなく理解していますが、代わりに情報を隠していますが、すべての細目を完全に理解しているかどうかはわかりません。 –

7

あなたが明示的に何かを書いていない推測された署名を見れば:

# module IntType = struct type t = int end ;; 
module IntType : sig type t = int end 

署名がtintであることを公開します。逆にあなたの署名、:

# module IntType : SOMETYPE = struct type t = int end ;; 
module IntType : SOMETYPE 

が本当にある:

# module IntType : sig type t end = struct type t = int end ;; 
module IntType : sig type t end 

これはあなたの問題を解決しているようだ:(

# module IntType : (SOMETYPE with type t = int) = struct type t = int end ;; 
module IntType : sig type t = int end 
# module IdentityInt = Identity(IntType) ;; 
module IdentityInt : sig val f : IntType.t -> IntType.t end 
# IdentityInt.f 0 ;; 
- : IntType.t = 0 

あなたは括弧を必要としませんが、彼らは助けます精神分析する)。基本的には、tが署名付きのintであるという事実を公開します。したがって、OCamlは等価性を知っています。IntType.t = int。

内部の詳細については、より詳しい知識のある人に任せておきます。

5

あなたが書くとき:

module IntType : SOMETYPE = struct type t = int end ;; 

あなたは正確にSOMETYPEするInTypeの署名を制約しています。これは、たとえば、タイプtが抽象型になっていることを意味します(その実装は、タイファーにとって未知です)。

したがってIdentityInt.f型は依然としてIntType.t -> IntType.tですが、署名制約を使用すると、式IntType.t = intをタイピング知識から明示的に削除しました。あなたが得るエラーメッセージはあなたにそれを正確に伝えます。

5

あなたのキーエラーはここにあった:

モジュールINTTYPE:SOMETYPE =構造体タイプt終了;;

あなたが署名SOMETYPEを帰するとき、それは不透明帰属だ、とintを持つアイデンティティが失われます。タイプIntType.tは抽象タイプになりました。

代わりに、署名SOMETYPE with type t = intに帰属する必要があります。

この転写物は、違いを示しています。モジュールと帰属周り

# module type SOMETYPE = sig type t end;; 
module type SOMETYPE = sig type t end 
# module IntType : SOMETYPE with type t = int = struct type t = int end;; 
module IntType : sig type t = int end 
# module AbsType : SOMETYPE = struct type t = int end;;     
module AbsType : SOMETYPE 

言語設計上の問題はよくリードデザイナーの1994 paper on modules, types, and separate compilationで覆われています。毛むくじゃらの数学の部分はすべてスキップすることができます。

+0

ありがとう、実際には 'モジュールIntType:SOMETYPE = struct型t = int end ;;私が使用した(私はREPLからコピーミスをしましたが、今は投稿を更新しました)です。それでも、まったく同じ結果が得られます。 't'型は指定されていても失われています。あなたと他のポスターが提案した構造体を使用しているときだけです(つまり、'モジュール型::型int型のSOMETYPE = struct型t = int end')。私の見解では、概念や構文を把握するのが最も直感的ではなく、OCamlマニュアルでむしろ光栄に思っています。 –

+0

@Menelaos、不透明な帰属は私たちのモジュールの皆さんに大いに愛されています。私の答えへのリンクを追加しました。 –

+0

多くのありがとう、ちょうどそれをダウンロードしました。 –

関連する問題