views:

672

answers:

1
+3  Q: 

Functors in Ocaml

I am having a bit of a problem with a functor (and it's resultant type). Below, I have a Set functor that uses an Ordered type. I actually used the set.ml that comes with ocaml for some guidance, but I seem to be doing everything ahhem right. I created an Ordered module with integers and applied it to the Set functor to get the last module on this code sample, IntSet.

The next line fails, when I try to insert an integer. I get the following type error:

Error: This expression has type int but is here used with type
         SetInt.elt = Set(OrdInt).elt

Don't get me wrong, the type system is correct here. The top level reports that the type of the SetInt.elt is Set(OrdInt).elt, but when I do the same operations to set up a Set using the one provided by ocaml the 'same' line is, SetInt.elt = OrderedInt.t. Seems like I should be getting SetInt.elt = Ordered.t.

This is so simple, I'm probably just missing some stupid detail! argh!

Please Note: I have simplified the member/insert functions here since this issue has to do with types.

module type Ordered =
  sig
    type t 
    val lt : t -> t -> bool
    val eq : t -> t -> bool
    val leq : t -> t -> bool
  end

module type S =
  sig
    type elt
    type t
    exception Already_Exists
    val empty  : t
    val insert : elt -> t -> t
    val member : elt -> t -> bool
  end

module Set (Elt:Ordered) : S = 
  struct
    type elt = Elt.t
    type t = Leaf | Node of t * elt * t
    exception Already_Exists
    let empty = Leaf
    let insert e t = t
    let member e t = false
  end

module OrdInt : Ordered =
  struct
    type t = int
    let lt a b = a < b
    let eq a b = a = b
    let leq a b = a <= b
  end

module IntSet = Set (OrdInt)

(* line that fails *)
let one_elm = IntSet.insert 1 IntSet.empty
+5  A: 

You need to change these two lines

module Set (Elt:Ordered) : S = 
module OrdInt : Ordered =

to

module Set (Elt:Ordered) : S with type elt = Elt.t = 
module OrdInt : Ordered with type t = int =

Without these, the modules will not have signatures that expose the types elt and t as int.

[Edit]: The set.ml doesn't have the 'with' bit, because there's a sml.mli, which declares the signature for the functor and it does have the 'with'. Also, OrdInt doesn't need 'with' if you don't explicitly specify a signature for it, like this:

module OrdInt =

You can also construct the set by defining the module in place:

module IntSet = Set (struct
 type t = int
 let lt a b = a < b
 let eq a b = a = b
 let leq a b = a <= b
end)
TrayMan