Functors vs First Class Modules

Is there anything that can be done with functors that cannot be done with functions that manipulate modules?

At a first look, it seems functions are strictly more powerful since they can accept both modules and values as arguments.

2 Likes

Yes, you can abstract over parametric type with functors but not with first-class modules.

module type MAPABLE = sig
  type 'a t
  val map : ('a -> 'b) -> 'a t -> 'b t
end

module F
(M : MAPABLE) 
(Param : sig type a type b val f : a -> b val x : a M.t end) = struct
  let res = M.map Param.f Param.x
end

module M = F (struct include List type 'a t = 'a list end)
(struct type a = int type b = string let f = string_of_int let x = [1; 2; 3] end)

module N = F (struct include Array type 'a t = 'a array end)
(struct type a = int type b = string let f = string_of_int let x = [|1; 2; 3|] end)

M.res;;
- : string list = ["1"; "2"; "3"]

N.res;;
- : string array = [|"1"; "2"; "3"|]
6 Likes

It was a good exercise to try to replicate the above functor with a function and seeing where things go wrong.

Thanks!

Note that with the experimental extension modular implicits, you can write this examples with plain functions (under the hood, functions with implicit parameters are implemented as first-class functors).

module type Map = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end

(* note the keyword `implicit' when you declare a module *)
implicit module Map_list = struct type 'a t = 'a list let map = List.map end

implicit module Map_array = struct type 'a t = 'a array let map = Array.map end

(* implicit module parameter must be put into curly braces *)
let map {M : Map} f x = M.map f x;;
val map : {M : Map} -> ('a -> 'b) -> 'a M.t -> 'b M.t = <fun>

map string_of_int [1; 2; 3];;
- : string Map_list.t = ["1"; "2"; "3"]

map string_of_int [|1; 2; 3|];;
- : string Map_array.t = [|"1"; "2"; "3"|]
3 Likes