Search code examples
moduleocamlfunctorfluentreason

Fluent Interface in ReasonML


Is there a way to get a module to return its own type using a functor submodule?

Example

module type A = {};
module type B = { let varB: int; };

module AMod : A = {};
module BMod : B = { let varB = 42; };

module Fn = (A: A, B: B) => A; /* Lets say this does some complex function that returns Type A */
module A2 = Fn(AMod, BMod);

What I want is a Fluent interface where a functor would be in A which returns its own type so it would look like

module type C = { module Fn: (B) => C };
module CMod : C = { Fn: (B) => C};

module C2 = CMod.Fn(BMod).Fn(BMod).Fn(BMod).Fn(BMod).Fn(BMod);

Is this possible in Reason or Ocaml?

Thanks


Solution

  • No, this is not possible. Your module type C would be recursive, which is not allowed. Such a form of recursion could very easily lead to undecidable type checking, given the expressive power of module types.

    It seems like you are trying to shoehorn an object-oriented pattern onto modules, which won't usually work -- ML modules are very much a functional language in nature. What's wrong with the following?

    module A2 = Fn(Fn(Fn(Fn(Fn(A, B), B), B), B), B)
    

    If you are interested in shortening the general pattern, you can actually implement a module combinator (in plain Ocaml, since I don't know Reason syntax well enough):

    module type FN = functor (X:A)(Y:B) -> A
    let rec fn n =
      if n = 0 then (module (functor (X:A)(Y:B) -> X) : FN)
      else (module (functor (X:A)(Y:B) -> (val fn (n-1))(X)(Y)))
    
    module A2 = (val fn 5)(AMod)(BMod)
    

    You could also write combinators that take a list of different B modules, though I wonder how useful that is going to be in practice.