Type alias across modules

Hi there, I found there are some references Module types / aliases, Type aliases for extensible types and Using module type of with module aliases in OCaml 4.07.* discussed before, but seems not suits for me.

I am writing a project with multiple modules, let’s say Temp, A and B
In module Temp I declared as below

(* temp.ml *)
open core
type t = int[@@deriving sexp, compare, hash]
include Comparable.Make (Int)

Then I declared a set in module A

(* a.ml *)
module TempSet = Set.Make(Temp)

Now I want to use TempSet module in B as below

(* b.ml *)
let foo (s : A.TempSet.t) = A.TempSet.iter s ~f:(fun x -> printf "%d " x)

However, now I get the compiler error in the lambda function as.

This expression has type A.TempSet.Elt.t but an expression was expected of type int

Since I generate TempSet based on int, so TempSet.Elt.t should be Temp.t , but why the type is inconsistent here?

Also, I found that if I write this function in module A, the error changes to

This expression has type A.Temp.t but an expression was expected of type int

Though still not working, but it makes more sense. So I guess this is about module namespace or type alias, is there anything I am missing?

Thank you!

Which version of ocaml and core are you using? I get different errors when trying your code.

Regardless, you have a couple of problems.

If your a.ml file is like shown above, then Set.Make will be the one from the stdlib: OCaml library : Set.Make, rather than the one from Core: Core.Set.Make · core v0.15.0 · OCaml Packages.

The simplest change to get your code working as is would be to add open Core (or open! Core) to the top of your a.ml file:

open! Core 
module TempSet = Set.Make(Temp)

This will be enough to get your code to compile (at least it will with OCaml 4.14 and Core v0.15.0).

Note that if you’re planning to use Core, you probably are going to want to open it in all your files. That way you won’t get the mixing Core modules with stdlib modules.

Actually, since you are using Core, you don’t need to bother with the Set.Make functor at all though. The Comparable.Make functor will give you Set and Map automatically. You just need to change the code a bit. (I will stick both modules into one file to keep it simple, but you could separate them if you need.)

open Core

module A = struct
  (* Define an internal module like this so we can pass it to the functor *)
  module T = struct
    type t = int [@@deriving sexp, compare]

  include T
  include Comparable.Make (T)

module B = struct
  let foo (s : A.Set.t) = A.Set.iter s ~f:(fun x -> printf "%d " x)

Now, if A.t is just an int, you may not need to do all that, but you may have a more complex type, and you wanted a set, and then you would.

Speaking of that, in your original temp.ml file, you have include Comparable.Make (Int) which happens to work because your type t is an int. But imagine that instead of type t = int you had something like type t = {name : string; age : int} or whatever, then you will need the inner module as above. Here you can see it works the same:

open Core

module Person = struct
  module T = struct
    type t = { name : string; age : int }[@@deriving sexp, compare]

  include T
  include Comparable.Make (T)

let people = Person.Set.of_list [...]
let () = Person.Set.iter people ~f:(...)
1 Like

Thank you for your reply! This is actually a simplified version of a complex project. I am using OCaml 4.12 and Core is 0.14.0.

You are right, it is not generating any error now in the simplified version after adding open Core. I didn’t try the simplified one and just use the error from the complex project, sorry for the inconvenience.

The suggestions for using Comparable.Make is also quite insightful. I will try this out!

I just realized the error I am facing is not reproducible in this simplified version. I guess its other subtle issues in my project. Again, thank you for your answer!

1 Like