Is someone may explain me functors. I would like to simple examples. When we should use functors?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With