|
2 | 2 | id: functors
|
3 | 3 | title: Functors
|
4 | 4 | description: >
|
5 |
| - Functors essentially work the same way as functions. The difference is that we are passing modules instead of values. |
| 5 | + In OCaml, a functor is a function at the module-level. Functors take modules as arguments and return a new module. |
6 | 6 | category: "Module System"
|
7 | 7 | ---
|
8 | 8 |
|
9 | 9 | # Functors
|
10 | 10 |
|
11 | 11 | ## Introduction
|
12 | 12 |
|
13 |
| -In this tutorial, we look at how to use a functor, how to write a functor, and show a couple of use cases involving functors. |
| 13 | +In this tutorial, we look at how to apply functors and how to write functors. We also show some use cases involving functors. |
14 | 14 |
|
15 |
| -As suggested by the name, a _functor_ is almost like a function. However, while functions are between values, functors are between modules. A functor takes a module as a parameter and returns a module as a result. A functor is a parametrised module. |
16 |
| - |
17 |
| -In mathematics, [functor](https://en.wikipedia.org/wiki/Functor) means something different. You don't need to know about those functors to understand OCaml's. |
| 15 | +As suggested by the name, a _functor_ is almost like a function. However, while functions are between values, functors are between modules. A functor takes a module as a parameter and returns a module as a result. A functor in OCaml is a parametrised module, not to be confused with a [functor in mathematics](https://en.wikipedia.org/wiki/Functor). |
18 | 16 |
|
19 | 17 | **Prerequisites**: [Modules](/docs/modules).
|
20 | 18 |
|
21 | 19 | ## Project Setup
|
22 | 20 |
|
23 |
| -This tutorial uses the [Dune](https://dune.build) build tool. Make sure you have installed version 3.7 or later. We start by creating a fresh project. We need a folder named `funkt` with files `dune-project`, `dune`, and `funkt.ml`. The latter two are created empty. |
| 21 | +This tutorial uses the [Dune](https://dune.build) build tool. Make sure you have installed version 3.7 or later. We start by creating a fresh project. We need a folder named `funkt` with files `dune-project`, `dune`, and `funkt.ml`. |
| 22 | + |
24 | 23 | ```shell
|
25 | 24 | $ mkdir funkt; cd funkt
|
26 | 25 | ```
|
27 | 26 |
|
28 |
| -**`dune-project`** |
| 27 | +Place the following in the file **`dune-project`**: |
29 | 28 | ```lisp
|
30 | 29 | (lang dune 3.7)
|
31 | 30 | (package (name funkt))
|
32 | 31 | ```
|
33 | 32 |
|
34 |
| -**`dune`** |
| 33 | +The content of the file **`dune`** should be this: |
35 | 34 | ```lisp
|
36 | 35 | (executable
|
37 | 36 | (name funkt)
|
38 | 37 | (public_name funkt)
|
39 | 38 | (libraries str))
|
40 | 39 | ```
|
41 | 40 |
|
42 |
| -Check this works using the `dune exec funkt` command, it shouldn't do anything (the empty file is valid OCaml syntax) but it shouldn't fail either. The stanza `libraries str` will be used later. |
| 41 | +Create an empty file `funkt.ml`. |
| 42 | + |
| 43 | +Check that this works using the `dune exec funkt` command. It shouldn't do anything (the empty file is valid OCaml syntax), but it shouldn't fail either. The stanza `libraries str` makes the `Str` module (which we will use later) available. |
43 | 44 |
|
44 | 45 | ## Using an Existing Functor: `Set.Make`
|
45 | 46 |
|
46 |
| -The standard library contains a [`Set`](/api/Set.html) module providing a data structure that allows set operations like union and intersection. You may check the [Set](/docs/sets) tutorial to learn more about this module, but it is not required to follow the present tutorial. To use the provided type and its associated [functions](/api/Set.S.html), it's necessary to use the functor provided by `Set`. For reference only, here is a shortened version of the interface of `Set`: |
| 47 | +The standard library contains a [`Set`](/api/Set.html) module which is designed to handle sets. This module enables you to perform operations such as union, intersection, and difference on sets. You may check the [Set](/docs/sets) tutorial to learn more about this module, but it is not required to follow the present tutorial. |
| 48 | + |
| 49 | +To create a set module for a given element type (which allows you to use the provided type and its associated [functions](/api/Set.S.html)), it's necessary to use the functor `Set.Make` provided by the `Set` module. For reference only, here is a shortened version of the interface of `Set`: |
47 | 50 | ```ocaml
|
48 | 51 | module type OrderedType = sig
|
49 | 52 | type t
|
50 | 53 | val compare : t -> t -> int
|
51 | 54 | end
|
52 | 55 |
|
53 |
| -module type S = sig |
54 |
| - (** This is the module's signature returned by applying `Make` *) |
55 |
| -end |
56 |
| -
|
57 | 56 | module Make : functor (Ord : OrderedType) -> S
|
58 | 57 | ```
|
59 | 58 |
|
60 |
| -Here is how this reads (starting from the bottom-up, then going up): |
| 59 | +Here is how this reads (starting from the bottom, then going up): |
61 | 60 | * Like a function (indicated by the arrow `->`), the functor `Set.Make`
|
62 |
| - - takes a module having `Set.OrderedType` as signature and |
63 |
| - - returns a module having `Set.S` as signature |
64 |
| -* The module type `Set.S` is the signature of some sort of set |
65 |
| -* The module type `Set.OrderedType` is the signature of elements of a |
| 61 | + - takes a module with signature `Set.OrderedType` and |
| 62 | + - returns a module with signature [`Set.S`](/api/Set.S.html) |
| 63 | +* The module type `Set.OrderedType` requires a type `t` and a function `compare`, which are used to perform the comparisons between elements of the set. |
66 | 64 |
|
67 |
| -**Note**: Most set operation implementations must use a comparison function. Using `Stdlib.compare` would make it impossible to use a user-defined comparison algorithm. Passing the comparison function as a higher-order parameter, as done in `Array.sort`, for example, would add a lot of boilerplate code. Providing set operations as a functor allows specifying the comparison function only once. |
| 65 | +**Note**: Most set operations need to compare elements to check if they are the same. To allow using a user-defined comparison algorithm, the `Set.Make` functor takes a module the specifies both the element type `t` and the `compare` function. Passing the comparison function as a higher-order parameter, as done in `Array.sort`, for example, would add a lot of boilerplate code. Providing set operations as a functor allows specifying the comparison function only once. |
68 | 66 |
|
69 | 67 | Here is what it can look like in our project:
|
70 | 68 |
|
|
0 commit comments