Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map modules to a module type in OCaml?

Tags:

ocaml

I want to define a module type that depends on other modules. I thought I could do it with a functor, but I believe functors are only mappings from modules to modules and it's not possible to use them to define mappings from a module to a module type.

Here's an example of what I'd like to do:

module type Field =
sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module type Func (F1 : Field) (F2 : Field) =
sig
  val eval : F1.t -> F2.t
end

module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2) =
struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end

I have a Field module type, like the real and rational numbers for example, and I want to define the type of functions Func from one field to another, which is F1.t -> F2.t for any two given modules F1, F2. With those module types in place, I can then define FuncField, which takes F1, F2, F and basically augments F.eval with add and mul.

When I run the code, I get a generic Error: Syntax error in the line where I define Func. Is there a way to define something like this in OCaml?

I'm not sure if this requires dependent types, but I'm mildly familiar with Coq, which has dependent types, and it didn't complain when I defined an equivalent construct:

Module Type Field.
  Parameter T : Type.
  Parameter add : T -> T -> T.
  Parameter mul : T -> T -> T.
End Field.

Module Type Func (F1 : Field) (F2 : Field).
  Parameter eval : F1.T -> F2.T.
End Func.

Module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2).
  Definition eval a := F.eval a.
  Definition add a b := F2.add (F.eval a) (F.eval b).
  Definition mul a b := F2.mul (F.eval a) (F.eval b).
End FuncField.
like image 773
Paula Vega Avatar asked Jan 19 '26 13:01

Paula Vega


2 Answers

Functors are functions from modules to modules. There is no such thing as a functor from module type to module type .... but you can cheat. :)

Unlike Coq, OCaml's modules are not fully dependent types, but they are "dependent enough" in this case. The idea is that modules can contain module types. Since we can't return a module type directly, we will simply return a module that contain one!

Your example become like that:

module type Field = sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module Func (F1 : Field) (F2 : Field) = struct
  module type T = sig
    val eval : F1.t -> F2.t
  end
end

module FuncField (F1 : Field) (F2 : Field) (F : Func(F1)(F2).T) = struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end

Note the Func(F1)(F2).T syntax, which says "apply the functor, and out of the result, take the module type T". This combination of functor application + field access is only available in types (either normal ones or module types).

I don't remember where I found that trick first, but you can see it in action "in production" in tyxml (definition, usage).

like image 154
Drup Avatar answered Jan 23 '26 00:01

Drup


Going outside the box a little since it doesn't seem like you really need a functor to accomplish what you describe. Simple module constraints might suffice:

module type Field =
sig
  type t
  val add : t -> t -> t
  val mul : t -> t -> t
end

module type Func =
sig
  type t1
  type t2
  val eval : t1 -> t2
end

module FuncField (F1 : Field) (F2 : Field) (F : Func with type t1 = F1.t and type t2 = F2.t) =
struct
  let eval a = F.eval a
  let add a b = F2.add (F.eval a) (F.eval b)
  let mul a b = F2.mul (F.eval a) (F.eval b)
end
like image 34
glennsl Avatar answered Jan 23 '26 00:01

glennsl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!