socumbersome
socumbersome

Reputation: 343

Multiple arguments in functor, OCaml

I have the following (fairly abstract) piece of OCaml code, in which the last line gives an error "Syntax error: ')' expected" which is extremely vague for me

module type AT =
sig
    type t
end;;
module type BT =
sig
    type t
    type a
end;;

module A : AT =
struct
    type t = int
end;;
module B : BT =
struct
    type a
    type t = a list
end;;

module type ABT =
sig
    type t
    module InsideA : AT
    module InsideB : BT
end;;

module ABT_Functor (AArg:AT) (BArg:BT with type a = AArg.t) : ABT =
struct
    module InsideA = AArg
    module InsideB = BArg
    type t = Sth of InsideA.t * InsideB.t
end;;

module ABTA = ABT_Functor (A);;
module ABTAB = ABT_Functor (A) (B:BT with type a = A.t);;

However, when I change the last line to

module ABTAB = ABT_Functor (A) (B);;

I get a signature mismatch error, saying

   Modules do not match:
     sig type t = B.t type a = B.a end
   is not included in
     sig type t type a = A.t end
   Type declarations do not match:
     type a = B.a
   is not included in
     type a = A.t

But I don't really understand that error. So, I hope it's quite clear what I want to achieve - I'd like to provide structures A and B to ABT_Functor functor, to obtain a structure ABTAB. How should I do that?

Upvotes: 1

Views: 969

Answers (2)

Andreas Rossberg
Andreas Rossberg

Reputation: 36118

Hm, your original version does not type-check either (the last line does not even parse), and for the same reason.

The reason is simple: in your definition of B you are implementing a as follows:

type a

Such a definition produces a distinct abstract type, i.e. a new type that is different from any other type. As a definition (not to be confused with a specification of a type in a signature), such a type is useless for pretty much anything but phantom types, because you cannot actually create any values of this type.

Nor can you change the definition of the type after the fact. This:

module Bint : sig type a = int end = B

is already ill-typed. Type B.a was defined as different from int. It only equals itself.

The problem you see with your functor application follows from there.

Upvotes: 1

didierc
didierc

Reputation: 14750

The general issue is that there are no constraints between module types AT and BT from the start, but you explicitely require one for your functor, so you need to provide one explicitely when using it if you force the module arguments to their minimal signatures.

In your precise case, the module A and B have been coerced respectively to AT and BT, without any additional information, thus making their inner types abstract. When passing them to the functor, even with additional type constraints, you cannot recover the implicitly existing relationship between A and B as it has been erased.

module A: AT with type t = int = struct type t = int end
module B: BT with type a = int = struct type a = int type t = int list end
(* with these definitions, you may use A and B without further ado as arguments to your functor *)

module ABTAB = ABT_Functor(A)(B) (* it works *)

Note that if you had not constrained A and B to begin with, it would have worked straight away.

module A = struct type t = int end
module B = struct type a = int type t = int list end


(* no constraints above *)

module ABTAB = ABT_Functor(A)(B) 

Upvotes: 2

Related Questions