Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml - functors - how to use? [closed]

Tags:

functor

ocaml

Is someone may explain me functors. I would like to simple examples. When we should use functors?

like image 323
user3024523 Avatar asked Oct 03 '22 08:10

user3024523


1 Answers

Functors, essentially are a way to write modules in terms of other modules.

A pretty classic example is the Map.Make functor from the standard library. This functor lets you define a map with a specific key type.

Here's a trivial and rather dumb example:

module Color = struct
    type t = Red | Yellow | Blue | Green | White | Black

    let compare a b =
        let int_of_color = function
            | Red -> 0
            | Yellow -> 1
            | Blue -> 2
            | Green -> 3
            | White -> 4
            | Black -> 5 in
        compare (int_of_color a) (int_of_color b)
end

module ColorMap = Map.Make(Color)

Loading this in ocaml shows the signature of the generated modules:

module Color :
  sig
    type t = Red | Yellow | Blue | Green | White | Black
    val compare : t -> t -> int
  end
module ColorMap :
  sig
    type key = Color.t
    type 'a t = 'a Map.Make(Color).t
    val empty : 'a t
    val is_empty : 'a t -> bool
    val mem : key -> 'a t -> bool
    val add : key -> 'a -> 'a t -> 'a t
    val singleton : key -> 'a -> 'a t
    val remove : key -> 'a t -> 'a t
    val merge :
      (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t
    val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
    val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
    val iter : (key -> 'a -> unit) -> 'a t -> unit
    val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
    val for_all : (key -> 'a -> bool) -> 'a t -> bool
    val exists : (key -> 'a -> bool) -> 'a t -> bool
    val filter : (key -> 'a -> bool) -> 'a t -> 'a t
    val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t
    val cardinal : 'a t -> int
    val bindings : 'a t -> (key * 'a) list
    val min_binding : 'a t -> key * 'a
    val max_binding : 'a t -> key * 'a
    val choose : 'a t -> key * 'a
    val split : key -> 'a t -> 'a t * 'a option * 'a t
    val find : key -> 'a t -> 'a
    val map : ('a -> 'b) -> 'a t -> 'b t
    val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t
  end

The simple module ColorMap = Map.Make(Color) has created a module that implements a map where the keys are colors. It's now possible to call ColorMap.singleton Color.Red 1 and get a map of red to the number 1.

Note that the use of Map.Make worked because the passed module (Color) satisfies the requirements of the Map.Make functor. The docs say the type of the functor is module Make: functor (Ord : OrderedType) -> S with type key = Ord.t. The : OrderedType means that the input module (Color) has to be consistent (I'm sure there's a more official term) with the OrderedType module signature.

To be consistent with OrderedType the input module has to have a type t and a function compare with signature t -> t -> int. In other words there has to be a way to compare values of type t. If you look at the types reported by ocaml that's exactly what Color supplies.

When to use functors is a much more difficult question as often there are several possible designs each with their own trade-offs. But most of the time you'll use functors when a library supplies them as the recommended way of doing something.

like image 50
Peter Minten Avatar answered Oct 13 '22 12:10

Peter Minten