Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indexing a set using first class module

Tags:

ocaml

Let's say I want to index all the elements of the set and store this indexing in a map. A working solution is to extend the Set module and create an inner functor:

module Make(M : Set.S) = struct
  include M

  module MakeIndexer(MM : Map.S with type key = elt) = struct
    let index_set set =
      let aux el (ix, acc) =
        (ix + 1, MM.add el ix acc)
      in
      M.fold aux set (0, MM.empty) |> snd
  end
end

Now, the use of the inner functor is a little cumbersome, I'd like to use an implementation using first class module. So far I got the following:

module Make(M : Set.S) = struct
  include M

  let index_map (module MM : Map.S with type key = elt) set =
    let aux el (ix, acc) =
      (ix + 1, MM.add el ix acc)
    in
    M.fold aux set (0, MM.empty) |> snd
end

I obtain the following error message

Characters 156-191:
  M.fold aux set (0, MM.empty) |> snd
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type int MM.t
      but an expression was expected of type int MM.t
      The type constructor MM.t would escape its scope

I understand that I'm using syntatic sugar and that the module is locally bound in the function, but is there a way to write the function using first class module?

like image 492
Raoul Supercopter Avatar asked Nov 22 '22 11:11

Raoul Supercopter


1 Answers

Updated version

If I understand you correctly you want to make index-map algorithm polymorhic w.r.t to mapping structure. Indeed, you need only two things from the whole set of Map operations: inital value and an addition operator. So you can just pass them as a parameter to your function.

module Make(T : Set.OrderedType) = struct
  module Set = Set.Make(T)

  let index_map (set : Set.t) (map : 'm) add : 'm =
    let aux el (ix, acc) =
      (ix + 1, add el ix acc) in
    Set.fold aux set (0, map) |> snd
end
like image 81
ivg Avatar answered Dec 19 '22 22:12

ivg