Hi there, I am wondering if I can pass a type in signature declaration, so I can declare a return signature of a functor more clearly.
For example
module type Flour = sig
type t
end
module type Bread = sig
type t
end
module Cook (F : Flour) : Bread = struct
type t = {material : F.t; sauce : 'a}
let cook (material: F.t) sauce = {material; sauce}
end
For some reasons, I need to declare the return signature of functor Cook explicitly. However, I have no idea how to declare cook function in signature Bread. Can I declare/reference a type from another signature when declaring a new signature? Something like
module type Bread = sig
type t
type r = Flour.t
val cook : r -> 'a -> t
end
I have complete my code, it looks like this. Notice that instead of using 'a, I replaced it with a explicit type.
module type Flour = sig
type t
end
module type Bread = sig
type i
type t
val cook : i -> int -> t
end
module Cook (F : Flour) : Bread = struct
type i = F.t
type t =
{ material : i
; cid : int
}
let cook (material : i) cid = { material; cid }
end
module F1 = struct
type t = { fid : int }
end
module B1 = Cook (F1)
let f1 : F1.t = { fid = 3 }
let b1 = B1.cook f1 3
However, the last line does not work, it says
This expression has type F1.t but an expression was expected of type B1.i
type t = { fid : int; }
In fact, F1.t and B1.i are of the same type, because B1 is created through Cook functor. Is there anything i am missing? Or do I misunderstand something
Yes, you are making the Cook functor’s output module too abstract, so the compiler ‘forgets’ the fact that the types are the same. The simplest way to solve it is to just not annotate the return type:
module Cook(F : Flour) = struct
...
end
In that case the compiler will infer the correct type and understand the type relationships automatically.
When you have a signature with abstract type, you can make it less abstract adding equation with with type t = expression. For instance you can specialize your Bread signature with type i = float.
module type Bread_with_float = Bread with type i = float;;
module type Bread_with_float =
sig type i = float type t val cook : i -> int -> t end
And so, you should write your functor signature:
module Cook (F : Flour) : Bread with type i = F.t = struct
...
end
Thank you for your solution! This is a simplified version of my code. In my original code, it is way more complex. The type of Flour can have variant from Cook(Flour). In this case, when I need to generate the new module through functor, I need to explicit provide the return signature for it because they are mutually referred.