Reputation: 6279
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
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