<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja"> 
  <HEAD>
    <title>Akihito Nagata's Page</title> 
    <META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
    <META http-equiv="Content-Style-Type" content="text/css">
    <meta name="keywords" content="akihito,nagata,ocaml,java,unix,linux,postgresql,html,stylesheet,cgi,thesis,type">
    <meta name="description" content="Akihito Nagata,プログラミングやlinuxなどのtips">    
    <meta name="robots" content="all">
    <link rel="stylesheet" href="/~ganat/stylesheet.css" type="text/css">
    <link rel="stylesheet" href="ocaml.css" type="text/css">
    <style type="text/css">
      
      pre.code { border-style : solid ;
                 border-width : 1px;
                 border-color : black;
                 padding : 5px;
                 background-color : #efe;
      }
      div.body { padding : 10px;
      }
    
    </style>
  </head>
  <body>
    <table summary="table" border=0 cellspacing=0 cellpadding=0>
	<tr>
	  <td valign="top">
	    <table summary="table" border=0 cellspacing=0 cellpadding=0>
		<tr>
		  <td>
		    <!-- 左上の画像 -->
		    <table summary="table" border=0 cellspacing=0 cellpadding=0>
			  <tr>
			    <td width=10><img alt="*" src="/~ganat/images/borders/pic_border_lt.jpg"></td>
			    <td width=120 style="background-image : url(/~ganat/images/borders/newpic_border_t.gif);">
			      <img alt="*" src="/~ganat/images/borders/white10x10.gif"></td>
			    <td witdh=10><img alt="*" src="/~ganat/images/borders/pic_border_rt.jpg"></td>
			  </tr>
			  <tr>
			    <td><img alt="*" src="/~ganat/images/borders/pic_border_l.jpg"></td>
			    <td><img alt="*" src="<!--#exec cgi="/~ganat/cgi-bin/todayimage.cgi"-->"></td>
			    <td style="background-image : url(/~ganat/images/borders/newpic_border_r.gif);vertical-align : top;">
			      <img alt="*" src="/~ganat/images/borders/white10x10.gif"></td>
			  </tr>
			  <tr>
			    <td><img alt="*" src="/~ganat/images/borders/pic_border_lb.jpg"></td>
			    <td style="background-image : url(/~ganat/images/borders/newpic_border_b.gif);text-align:left;">
			      <img alt="*" src="/~ganat/images/borders/white10x10.gif"></td>
			    <td><img alt="*" src="/~ganat/images/borders/newpic_border_rb.gif"></td>
			  </tr>
		      </table>
		  </td>
		</tr>
		<tr>
		  <td class="menu" valign="top">
		    <!-- MENU -->
		    <div class="menutitle"><img alt="menu" src="/~ganat/images/menutitle.jpg"></div>
		    <div class="menu"><table width="140">
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/index.html">Top Page</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/ocaml/ocaml.html">Ocaml</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/java/java.html">Java</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/diary.html">Theses</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/presentation.html">Presentation</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/survey/index.html">Survey</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/unix/unix.html">Unix Tips</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/memo/index.html">Memo</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/link.html">LINK</a></td></tr>
<tr style="text-align : right; "><td><a class="menu" href="/~ganat/cgi-bin/nagabbs/nagabbs.cgi">BBS</a></td></tr>
</table>
</div>
		  </td>
		</tr>
	    </table>
	  </td>
	  <td>
      <table summary="table" border=0 cellspacing=0 cellpadding=0>
		<tr>
		  <td valign="top" style="text-align : center;">
		    <!-- 題名 -->
		    <!-- <div class="title">GANAT PAGE</div> -->
		    <img alt="Akihito Nagata's Page" src="/~ganat/images/title.gif">
		  </td>
		</tr>
		<tr>
		  <td>
		    <!-- メイン -->
		    <table summary="table" border=0 cellspacing=0 cellpadding=0>
			<tr>
			  <td width="10"><img alt="|" src="/~ganat/images/borders/vline_t.jpg"></td>
			  <td></td>
			  <td></td>
			</tr>
			<tr>
			  <td style="background-image:url(/~ganat/images/borders/vline.jpg);"><img alt="|" src="/~ganat/images/borders/vline.jpg"></td>
			  <td><div class="main">
    <div class="body">
      <div class="title"><span class="title">OcamlのModuleシステム<img alt="rakuda" src="/~ganat/images/rakuda.gif"></span></div>

      <p>
      分割コンパイルすることにより、モジュールを作成する場合もあるが、ここではそれ以外の方法として直接モジュールを作る方法を３つのキーワード:structures,signatures,functorsを中心に説明する。
      </p>
      <p>
	分割コンパイルした場合と比較すると、signatureは.mliに、structureは.mlに相当する。分割コンパイルとの違いは、一つのファイルに複数のモジュールが定義できること、一つのsignatureを複数のmoduleに適用できることである。signatureを共有することによりコードの再利用性を高めることができる。
      </p>
      <p>
	Ocamlではこの他のfunctorとパラメータ化されたmoduleを作ることができる。functorは引数として与えられたstructureからstructureを作る。functorにより、より一般的なstructureを作ることができる。
      </p>
      
      <h1>モジュールのsignature</h1>
      <p>
      signatureは<span class="blue">module type</span>宣下元により定義される。
	<pre class="code">
<span class="blue">module type</span> <span class="i">Name</span> = sig <span class="i">signature</span> end
      </pre>
      signature名は大文字から始まらなくてはならない。signatureに含めることができるのは
      <ul>
	<li>type 宣言</li>
	<li>exception 定義</li>
	<li>メソッドの型定義(val)</li>
	<li>openステートメントによる他のsignatureの名前空間のopen</li>
	<li>includeにより他のsignatureのインクルード</li>
	<li>ネストしたsigunatureの宣言。</li>
      </ul>
      である。
      </p>
      <p>
	signatureはインタフェース中でも、その内部の実装中でもOcamlのtopでも定義できる。
      </p>
      <p>
	例として有限集合を考える。signatureはsetが持つべき型宣言を定義する。Ocamlのtoploopで次を宣言する。
      </p>
      <p>
      <pre class="code">
# module type FsetSig =
  sig
     type 'a t
     val empty : 'a t
     val mem : 'a -&gt; 'a t -&gt; bool
     val insert : 'a -&gt; 'a t -&gt; bool
  end;;
module type FsetSig =
  sig
     type 'a t
     val empty : 'a t
     val mem : 'a -&gt; 'a t -&gt; bool
     val insert : 'a -&gt; 'a t -&gt; bool
  end
      </pre>
      もし既存のsignatureがあるならばincludeを使って以下のように書ける。
      <pre class="code">
# module type FsetDSig =
  sig
      include FsetSig
      val delete : 'a -&gt; 'a t -&gt; 'a t
  end;;
module type FsetSig =
  sig
     type 'a t
     val empty : 'a t
     val mem : 'a -&gt; 'a t -&gt; bool
     val insert : 'a -&gt; 'a t -&gt; bool
     val delete : 'a -&gt; 'a t -&gt; 'a t
  end
      </pre>
      </p>
      <h1>モジュールのstructure</h1>
      <p>
	structureは<span class="blue">module</span>キーワードを使って定義される。
	<pre class="code">
<span class="ブル">モジュール</スパン> <span class="i">Name</スパン> = struct <span class="i">implementation</span> end
      </pre>
      モジュール名も大文字から始まらなくてはならない。モジュールの定義に含めることができるのは
      <ul>
	<li>type 定義</li>
	<li>exception定義</li>
	<li>method定義(let)</li>
	<li>open宣言による他のモジュールの名前空間のオープン</li>
	<li>include宣言による他のモジュールの内容のインクルード</li>
	<li>signature定義</li>
	<li>ネストしたstructureの定義</li>
      </ul>
      である。モジュールの例として平行二分探索木を定義してみると、
      <pre class="code">
#module Fset =
   struct
      type color = 
         Red
       | Black

      type 'a t = 
         Node of color * 'a t * 'a * 'a t
       | Leaf
  
      let empty = Leaf
   
      let rec mem x = function
         Leaf -&gt; false
       | Node (_, a, y, b) -&gt;
            if x &lt; y then mem x a
            else if x > y then mem x b
            else true

      let balance =  ... 

      let insert x s = ...
   end;;
module Fset : 
  sig 
    type color = | Red | Black
    and 'a t = | Node of color * 'a t * 'a * 'a t | Leaf
    val empty : 'a t
    val mem : 'a -&gt; 'a t -&gt; bool
    val balance : color * 'a t * 'a * 'a t -&gt; 'a t
    val insert : 'a -&gt; 'a t -&gt; 'a t
  end;;
# Fset.empty;;
- : 'a Fset.t = Fset.Leaf
# Fset.balance;;
- : Fset.color * 'a Fset.t * 'a * 'a Fset.t -&gt; 'a Fset.t = &lt;fun&gt;
      </pre>
     となる。
      </p>
      <h2>signatureの適用</h2>
      <p>
	structureにsignatureを明示的に適用しない場合はデフォルトのsignatureが使われ、その場合はstructure内の全ての定義が外から見えるようになってしまう。
      </p>
      <p>
	structureにsignatureを適用するには":"を使う。
	<pre class="code">module Name : SigName = struct implementation end</pre>
      先程定義したsignature FsetSig をFsetに適用する例をしめす。
      <pre class="code">
module Fset : FsetSig =  
   struct
      type color = 
         Red
       | Black

      type 'a t = 
         Node of color * 'a t * 'a * 'a t
       | Leaf
  
      let empty = Leaf
   
      let rec mem x = function
         Leaf -&gt; false
       | Node (_, a, y, b) -&gt;
            if x &lt; y then mem x a
            else if x > y then mem x b
            else true

      let balance =  ... 

      let insert x s = ...
   end;;
module Fset : FsetSig
# Fset.empty;;
- : 'a Fset.t = &lt;abstr&gt;
# Fset.balance;;
Unbound value Fset.balance
      </pre>
      signatureを適用することにより、'a tの定義が抽象化され、balanceは外部から見られなくなった。
      </p>
      <h1>Functor</h1>
      <p>
	有限集合を表すモジュールを実装しようとした場合問題となるのは、元から用意されている "&lt;" 演算子を使って比較を行っているところである。&lt;演算子は実装依存であり、常に望んでいる順序付けを行ってくれるとは限らない。
      </p>
      <p>
	この問題に対処するために、独自の比較関数を定義することにする。しかし、そうすると集合の中身の型に付いて異なる実装が必要となる。これに対処するためにfunctorを用いる。functorとはモジュール上の関数であり、モジュールを引数にとりモジュールを返す。functorは<span class="blue">functor</span>キーワードを用いて定義するか、それに変わる構文を用いて定義することができる。
	<pre class="code">
module Name = functor (ArgName : ArgSig) -&gt;
         struct implementation end
        module Name(Arg : ArgSig) = 
         struct implementation end
      </pre>
      有限集合のモジュールの例だと要素の型eltを持ち、比較関数compareを持つstructureを定義する必要があるだろう。compare関数は以下のどれかを返すとする。
      <ol>
	<li>第1引数が第2引数より小さければ負の整数を返す。</li>
	<li>二つの引数が等しければ0を返す。</li>
	<li>第1引数が第2引数より大きければ正の整数を返す。</li>
      </ol>
      これのsignatureは以下のように書ける。
      <pre class="code">
module type EltSig =
sig
   type elt
   val compare : elt -&gt; elt -&gt; int
end
      </pre>
      </p>
      <p>
	これに伴ってFsetSigもある特定のeltが扱えるように書き換える必要がある。ここで注意すべきは この有限集合はそれ自体polymorphicではない点である。
	<pre class="code">
module type FsetSig =
sig
   type elt
   type t

   val empty : t
   val mem : elt -&gt; t -&gt; bool
   val insert : elt -&gt; t -&gt; t
end
</pre>
      </p>
      <p>
      次に集合の定義をfunctorとして定義し直す。実装はeltの定義を導入し、memとinsertは比較関数を使うように書き直される。
<pre class="code">
# module MakeFset (Elt : EltSig) =
  struct
     type elt = Elt.elt
     type color : = ...
     type t =
        Node of color * t * elt * t
      | Leaf
   
     let empty = Leaf
     
     let rec mem x = function
        Leaf -&gt; false
      | Node (_, a, y, b) -&gt;
          let i = Elt.compare x y in
             if i < 0 then mem x a
             else if i > 0 then mem x b
             else true

     let balance = ...
    
     let insert x s = ...
  end;;
module MakeFset :
  functor(Elt : EltSig) -&gt;
    sig
      type elt = Elt.elt
      and color = | Red | Black
      and t = | Node of color * t * elt * t | Leaf
      val empty : t
      val mem : Elt.elt -&gt; t -&gt; bool
      val balance : color * t * elt * t -&gt; t
      val insert : elt -&gt; t -&gt; t
    end
      </pre>
      </p>
      <p>
	このfunctorは引数としてsignature EltSigを持つモジュールEltを受け取り、最後に表示されているようなsignatureを持つモジュールを返す。最後に返されるモジュールは中身が全て見えてしまっているので、これが適当でない場合には
      <pre class="code">
# module MakeFset (Elt : EltSig) : FsetSig =
  struct 
      ...
  end;;
module MakeFset : functor(Elt : EltSig) -&gt; FsetSig
      </pre>
      のように返り値のモジュールのsignatureを指定する。
      </p>
      <h2>functorの使用</h2>
      <p>
	functorで定義されたモジュールを使うにはある特定のEltSigのsignatureを持つモジュールの実装を適用する必要がある。例として整数の型と比較関数を持つモジュールを定義する。この場合は比較関数は整数の差で実装できる。
      <pre class="code">
# module Int = 
  struct 
     type elt = int
     let compare = (-)
  end;;
module Int : 
  sig 
     type elt = int 
     val compare : int -&gt; int -&gt; int 
  end
# Int.compare 3 5;;
- : int = -2
      </pre>
      </p>
      <p>
	signature EltSigではelt型はabstractとなる。IntモジュールはEltSigを満たす必要があるが、eltの定義が見える状態にしておきたいのでsignatureは適用しない。
	<pre class="code"> 
# module Int' = (Int : EltSig);;
module Int' : EltSig
# Int'.compare 3 5;;
Characters 13-14:
This expression has type int but is here used with type Int'.elt
      </pre>
    </p>
      <p>
	functorは<span class="blue">functor_name(arg_name)</span>という構文で適用される。整数の有限集合のモジュールを作るにはMakeFset functorにIntモジュールを適用する。
	<pre class="code">
# module IntSet = MakeFset (Int);;
  module IntSet : 
    sig
      type elt = MakeFset(Int).elt
      and t = MakeFset(Int).t
      val empty : t
      val mem : elt -&gt; t -&gt; bool
      val inset : elt -&gt; t -&gt; t
    end
# IntSet.empty;;
- : IntSet.t = &lt;abstr&gt;
# IntSet.insert 1 IntSet.empty;;
- : IntSet.t = IntSet.Node (IntSet.Leaf, 1, IntSet.Leaf)
      </pre>
	<pre class="code">
# module IntSet' = MakeFset(Int');;
module IntSet' :
  sig
    type elt = Int'.elt
    and t = MakeFset(Int').t = Node of t * elt * t | Leaf
    val empty : t
    val mem : Int'.elt -&gt; t -&gt; bool
    val insert : elt -&gt; t -&gt; t
  end
# IntSet'.insert 1 IntSet'.empty;;
                 ^
This expression has type int but is here used with type
  IntSet'.elt = Int'.elt
</pre>
      </p>
      <p>
      </p>
    </div>
  </div></td>
			  <td></td>
			</tr>
			<tr>
			  <td><img alt="|" src="/~ganat/images/borders/vline_b.jpg"></td>
			  <td></td>
			  <td></td>
			</tr>
		    </table>
		  </td>
		</tr>
	    </table>
    </td>
  </tr>
  </table>
    <div><a href="/~ganat/old/index.html">前のページはこちら</a></div>
  </body> 
</html>