geckos
geckos

Reputation: 6279

How to receive types built from functors as argument to functions in OCaml?

I'm studying functors, and I was trying to receive a Module.t as argument where Module is the result of a functor call SomeFunctor(sig type t = int end) but I receive Unbound type constructor FooInt.t

Here is the code

module type Foo_S = sig
  type t
end

module type Foo = sig
  type t
  val id : t -> t
end

module FooExtend(Arg : Foo_S) : (Foo with type t := Arg.t) = struct
  let id a = a
end

module FooInt = FooExtend(Int)
module FooString = FooExtend(String)

let () =
  assert (FooInt.id 1 = 1);
  assert (FooString.id "x" = "x")

module FooSimple = struct type t = int end

let foo (x : FooInt.t) = (* This doens't compile: Unbound type constructor FooInt.t *)
  FooInt.id x

let foo' (x : FooSimple.t) = (* This works fine *)
  FooInt.id x

Upvotes: 4

Views: 354

Answers (1)

glennsl
glennsl

Reputation: 29106

Two changes are needed, 1) type t needs to be defined in the module, and 2) don't use destructive substitution:

module FooExtend(Arg : Foo_S) : (Foo with type t = Arg.t) = struct
  type t = Arg.t
  let id a = a
end

The problem is that destructive substitution (type t := Arg.t) replaces every occurrence of t with Arg.t. Instead you want to specify type equality, using a "sharing constraint" (type t = Arg.t).

Notice the difference in the resulting module signature between the two:

module FooExtend(Arg : Foo_S) : (Foo with type t := Arg.t) = struct
  type t = Arg.t
  let id a = a
end

module FooExtend : functor (Arg : Foo_S) -> sig 
  val id : Arg.t -> Arg.t
end
module FooExtend(Arg : Foo_S) : (Foo with type t = Arg.t) = struct
  type t = Arg.t
  let id a = a
end

module FooExtend : functor (Arg : Foo_S) -> sig
    type t = Arg.t
    val id : t -> t
end

Upvotes: 5

Related Questions