ocamllocally-abstract-type

Is there a way to parametrize a module on a type or escape a type from a module in OCaml?


Is there a way to either parametrize a module on a type or escape a type from a module in OCaml? Basically, I'd like to write some routines that are parametrized on a floating point type and still have access to the operators like (+.), (-.), etc. Certainly, we can write a floating point module like

module type REAL = sig
    type t
    val real : float->t
    val (+.) : t->t->t
    val (-.) : t->t->t
    val ( *. ) : t->t->t
    val (/.) : t->t->t
end

which has a really basic implementation for normal floats

module MyReal : REAL = struct
    type t=float
    let real x=x
    let (+.) x y = x+.y  
    let (-.) x y = x-.y
    let ( *. ) x y = x*.y
    let (/.) x y = x/.y
end

Then, I tried to use this module locally in a module with the code

let double (type real) (module Real:REAL with type t = real) x =
    let open Real in
    x+.x

This function has the type that I desire

val double : (module REAL with type t = 'a) -> 'a -> 'a = <fun>

However, if I run it, the compiler will complain

# double (module MyReal) 1.0;;
Error: This expression has type float but an expression was expected of type
         MyReal.t

Certainly, we can use the injection function from the module

# double (module MyReal) (MyReal.real 1.0);;
- : MyReal.t = <abstr>

but then the resulting type is abstract and not a float. Ultimately, I'd like a way to have the function double return an exposed type. If at all possible, I don't want to use another function within the REAL module to convert t->float. I want the actual type t to be exposed somehow. Also, I'd like a way to do this by using the module locally rather than a functor parameterized on REAL.


Solution

  • You gave MyReal a type constraint too restricted: MyReal : REAL. It's type t's implementation is hidden by the constraint. At the use of MyReal, double (module MyReal) 1.0, the unification of type t and float fails since you hide the fact t = float.

    A fix is the following:

    module MyReal : REAL with type t = float = struct
      ...
    end
    

    but the best way is to let OCaml infer the most general type for MyReal by itself:

    module MyReal = struct
      ...
    end
    

    Here, the relationship of MyReal and REAL is less clear but OCaml's module typing is clever enough to find MyReal has an instance of module REAL with type t = 'a.