Sharing Types Between Functor Arguments


#1

I am trying to share types between functor arguments like the following code. What’s a good way to do this?

module MyFilter = {
  
  module type Filter = {
   type filterType;
   type state = {data: filterType};
   let toString: filterType => string;
  };

  type colorFilter =
    | Yellow
    | Red

  module RedFilter: Filter = {
   type filterType=colorFilter;
   type state = {data: filterType};
   let toString = (color: filterType) => "Red";
  };

  module YellowFilter: Filter = {
   type filterType=colorFilter;
   type state = {data: filterType};
   let toString = (color: filterType) => "Yellow";
  };

};

let yellow: MyFilter.colorFilter = Yellow;
let red: MyFilter.colorFilter = Red;

MyFilter.YellowFilter.toString(yellow);
MyFilter.RedFilter.toString(red);

The code generates an error:

We've found a bug for you!
OCaml preview 32:40-45

This has type:
  MyFilter.colorFilter
But somewhere wanted:
  MyFilter.YellowFilter.filterType

Here’s the code in the playground:


#2

You need to expose the fact that the type of filterType = colorFilter in both RedFilter and YellowFilter. e.g.

module RedFilter: Filter with type filterType = colorFilter = { ... }
module YellowFilter: Filter with type filterType = colorFilter = { ... }

Without doing that, all you’ve exposed is the fact that both the Red and Yellow Filter module satisfy the Filter module type, so they both have a filterType, but you haven’t exposed a way for the compiler to know that those are actually the same type.

Maybe a more intuitive explanation is the following example (I didn’t check this for compilation, you can think of it as pseudo-code):

module type HasATypeT = { type t; }
module MyString : HasATypeT = { type t = string }
module MyFloat : HasATypeT = { type t = float }

You definitely wouldn’t want the compiler just assuming that MyString.t and MyFloat.t are the same type in this case. Your example basically looks the same as this to the compiler.

Compiling version of your code here: