7

Java の OO システムの代わりに OCaml のモジュール システムを使用する方法についてのブログ エントリを書いています (楽しい視点です)。強制について理解できないものに出くわしました。以下は、基本モジュールとそれを含む 2 つのモジュールです。

module M = struct
  type t = int
  let make () = 1
end   
module A = struct
  include M
end
module B = struct
  include M
end

At と Bt は同じ型になりました。なんで?やれば一目瞭然

let a = A.make();;
let b = B.make();;
[a;b] --> A.t list (* ? *)

プライベートな型の略語でこれを防ぎ、それらを同じリストに入れたい場合は強制を使用することが可能であることを私は知っています。私の質問は、なぜこれがまだ行われていないのですか? コンパイラはそれをどのように認識し、同じ基本型A.tからB.t来ているのでしょうか?

よろしく
オーレ

4

2 に答える 2

11

これら 2 つのモジュールに互換性を持たせたい場合がたくさんあります。より単純な使用例は次のとおりです。

module Hashtbl = struct ... (* definition in the stdlib *) end

module ExtHashtbl = struct ... (* my own layer on top of it *) end

ExtHashtbl.tと互換性を持たせたいHashtbl.tので、ExtHashtblコードの途中で を使用して機能したり、自分のものではなくライブラリHashtbl.tについてしか知らない他の誰かによって構築された値を操作したりできます。Hashtbl

ML モジュールの理論には、「強化」と呼ばれる操作があります。これは、モジュール定義を可能な限り多くの方程式で強化し、それらを署名で公開します。アイデアは、より抽象化したい (数式を減らしたい) 場合は、いつでも型シグネチャを使用してそれを制限できるため、数式を使用する方が厳密に一般的であるということです。

ファンクターの場合は状況が少し異なります。A と B を単純なモジュールとして定義する代わりに、それらを空のシグネチャのファンクタにしたと考えてください。

module A (U : sig end) = struct include M end
module B (U : sig end) = struct include M end

ML モジュール システムには、ファンクターの 2 つの異なる概念があります。「ジェネレーティブ」と呼ばれるもの (ファンクターの各呼び出しは、他の呼び出しと互換性のない「新しい」型を生成します) と、「アプリカティブ」と呼ばれるもの (すべて等しい引数でのファンクターの呼び出しには、互換性のある型があります)。OCaml システムは、名前付きのモジュール引数 (より一般的にはpath ) を使用してインスタンス化するとアプリケーション的に動作し、名前のないモジュール引数を使用してインスタンス化すると生成的に動作します。

Xavier Leroy の 2000 年の論文A Modular Module System (PDF) (Web ページA few papers on Camlから)で、OCaml モジュール システムについて知りたいと思っていたよりもはるかに多くのことを学ぶことができます。上記で説明したすべての状況のコード例を以下に示します。

ML モジュール システムに関する最近の研究、特に Anreas Rossberg、Derek Dreyer、Claudio Russo によるものは、「適用的」ファンクターと「生成的」ファンクターの古典的な区別に異なる視点をもたらす傾向があります。彼らは、「純粋な」ファンクターと「不純な」ファンクターに対応する必要があると主張しています。アプリケーションが副作用を実行するファンクターは常に生成的であるべきですが、純粋な項のみをもたらすファンクターはデフォルトでアプリケーション的であるべきです抽象化を提供します)。

module type S = sig
  type t
  val x : t
end;;

module M : S = struct
  type t = int
  let x = 1
end;;

(* definitions below are compatible, the test type-checks *)
module A1 = M;;
module B1 = M;;
let _ = (A1.x = B1.x);;

(* definitions below are each independently sealed with an abstract
   signature, so incompatible; the test doesn't type-check *)
module A2 : S = M;;
module B2 : S = M;;
let _ = (A2.x = B2.x);;
(*This expression has type B2.t but an expression was expected of type A2.t*)


(* note: if you don't seal Make with the S module type, all functor
   applications will be transparently equal to M, and all examples below
   then have compatible types. *)
module Make (U : sig end) : S = M;;

(* same functor applied to same argument:
   compatible (applicative behavior) *)
module U = struct end;;
module A3 = Make(U);;
module B3 = Make(U);;
let _ = (A3.x = B3.x);;

(* same functor applied to different argument:
   incompatible (applicative behavior) *)
module V = struct end;;
module A4 = Make(U);;
module B4 = Make(V);;
let _ = (A4.x = B4.x);;
(* This expression has type B4.t = Make(V).t
   but an expression was expected of type A4.t = Make(U).t *)

(* same functor applied to non-path (~unnamed) arguments:
   incompatible (generative behavior) *)
module A5 = Make(struct end);;
module B5 = Make(struct end);;
let _ = (A5.x = B5.x);;
(* This expression has type B5.t but an expression was expected
   of type A5.t *)
于 2013-07-02T13:57:20.703 に答える
4

まだ行われていないことはわかりませんが、次のとおりです。

于 2013-07-02T04:28:20.113 に答える