OCaml

練習問題 11.1 ファンクターに与える引数のシグネチャを指定する

練習問題 11.1 ファンクタの引数にシグネチャを与える

下の

module OrderedInt' : OrderedType =
  struct
    type t = int
    let compare i j = i - j
  end;;

module IntSet' = MakeSet (OrderedInt');;

のように、MakeSet に与える引数のシグネチャを OrderedType として明示的に指定した場合、このモジュール IntSet’ は、IntSet と、どういった点で異なっているでしょうか。

問題文の言うている状況は、以下のようなことと考えた。

つまり、ファンクターで生成したモジュールにシグネチャを与えるということではなく、ファンクターの引数であるストラクチャ(モジュール)にシグネチャを与えた場合、どうなるかということと理解した。

module type OrderedType =
  sig
    type t
    val compare : t -> t -> int
  end

module MakeSet (Order : OrderedType) : 
    sig
      type elt = Order.t
      type t
      val empty : t
      val mem : elt -> t -> bool
      val add : elt -> t -> t
      val inter : t -> t -> t
      val elements : t -> elt list
    end
=
  struct
    type elt = Order.t
    type t = elt list
    
    let empty = []

    let rec mem elt = function
        [] -> false
      | x :: rest ->
        let r = Order.compare elt x in
        (r = 0) || ((r > 0) && mem elt rest)
    (* if elt = x then true else mem elt rest は、あかんの?*)

    let rec add elt = function
        [] -> [elt]
      | (x :: rest as s) ->
        match Order.compare elt x with
        0 -> s
        | r when r < 0 -> elt :: s
        | _ -> x :: (add elt rest)
    (* このリストは、昇順にならんでいるリストやな *)

    let rec inter s1 s2 =
      match (s1, s2) with
        (s1, []) -> []
      |([], s2) -> []
      |((e1::rest1 as s1), (e2::rest2 as s2)) ->
        match Order.compare e1 e2 with
        0 -> e1 :: inter rest1 rest2
        | r when r < 0 -> inter rest1 s2
        | _ -> inter s1 rest2

    let rec elements s = s
  end

(* 比較のために、シグネチャのないモジュールを用意した *)
module OrderedInt  =
  struct
    type t = int
    let compare i j = i - j
  end
(*
module OrderedInt : sig type t = int val compare : t -> t -> t end
 *)
  
module IntSet = MakeSet (OrderedInt);;

(*
module IntSet :
  sig
    type elt = int
    type t = MakeSet(OrderedInt).t
    val empty : t
    val mem : elt -> t -> bool
    val add : elt -> t -> t
    val inter : t -> t -> t
    val elements : t -> elt list
  end
 *)
  
(* こちらは問題文に書かれているシグネチャつきのモジュールである *)  
module OrderedInt' : OrderedType  =
  struct
    type t = int
    let compare i j = i - j
  end
(*
module OrderedInt' : OrderedType
 *)

module IntSet' = MakeSet (OrderedInt');;
(*
module IntSet' :
  sig
    type elt = OrderedInt'.t
    type t = MakeSet(OrderedInt').t
    val empty : t
    val mem : elt -> t -> bool
    val add : elt -> t -> t
    val inter : t -> t -> t
    val elements : t -> elt list
  end
 *)
                        
  
let s1 = IntSet.add 2 (IntSet.add 1 IntSet.empty);;
  (* val s1 : IntSet.t = <abstr> *)
IntSet.elements s1;;
  (* - : int list = [1; 2] *)

let s2 = IntSet'.add 2 (IntSet'.add 1 IntSet'.empty);;
  (* Error: This expression has type int but an expression was expected of type IntSet'.elt *)

解答

OrderedInt’ と、シグネチャつきのモジュールを引数として MakeSet に渡すと、type elt = OrderedInt’.t となる。

そののち、IntSet’.add 1 IntSet’.empty などとすると、型が合わないというエラーが出る。
Error: This expression has type int but an expression was expected of type IntSet’.elt

こんなんで、答えになっているんだろうか?
どこか勘違いしているような気がする。