<jupyter_start><jupyter_text>Modules  Structures  Defining structures All OCaml programs are organised into *modules*. The simplest form of module is a *structure*. You can think of structures as collections of definitions. Structures can be created using the `module` and `struct` keywords:<jupyter_code>module M = struct
  type t = T
  let x = T
end<jupyter_output><empty_output><jupyter_text>Accessing structure components The components of a module can be accessed using the `.` operator:<jupyter_code>let y = M.x<jupyter_output><empty_output><jupyter_text>Note that the `.` operator works for types as well as values: the `y` variable defined above has type `M.t`.  Files as structures In OCaml every source file defines a structure. For example, a file called `foo.ml` would be treated as the definition of a module called `Foo`. We have already used such modules in earlier examples: for instance the `List.map` function of the standard library is defined in a file called [`list.ml`](https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.mlL90).  Signatures and abstraction Just as all values in OCaml have a type, all modules have a *module type*. As you can see from the output, the module `M` defined above has the module type:````sig  type t = T  val x : tend````This means that it contains a variant type `t` with a single `T` constructor, and a value `x` of type `t`. The module types of structures -- like the one above -- are often called *signatures*.  Signature ascription Whilst OCaml will infer the module type of a structure from its definition, you can also ascribe it a more restricted signature. This allows us to hide some of the details of the structure:<jupyter_code>module IntSet : sig
  type t
  val empty: t
  val mem: int -> t -> bool
  val add: int -> t -> t
end = struct
  type t = int list

  let empty = []

  let mem i s =
    let is_i j = (i = j) in
      List.exists is_i s

  let add i s =
    if mem i s then s
    else i :: s
end<jupyter_output><empty_output><jupyter_text>Here we create an `IntSet` module with a type `t` representing sets of integers.<jupyter_code>let s = IntSet.add 6 (IntSet.add 5 IntSet.empty)

let b = IntSet.mem 6 s<jupyter_output><empty_output><jupyter_text>By not including the defintion of `t` in the signature, we hide the implementation of `IntSet`. This means that users of our set type cannot depend on the fact we have implemented it using lists.<jupyter_code>let r = 4 :: s<jupyter_output><empty_output><jupyter_text>Later we can switch to a more efficient implementation using trees safe in the knowledge that this will not break existing code using `IntSet`.Types with hiddent definitions -- like `t` above -- are called abstract types. OCaml's support for abstraction is one of its most important and powerful features.  Signatures for files To add a signature to the module represented by a file we add an interface file. For example, if a file called `foo.ml` defines a structure called `Foo` then `foo.mli` defines the signature of `Foo`. Corresponding to the [`list.ml`](https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.ml) in the OCaml standar library, we have [`list.mli`](https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.mli) which describes the signature of the list interface.  FunctorsIn OCaml, functors are module level functions that take modules as arguments and return other modules as results. We had earlier seen an identity function:<jupyter_code>let id (x : int) = x<jupyter_output><empty_output><jupyter_text>that takes some integer and returns the same. We can define a similar identity functor at the module level. First, let us define a module type which only containts the type alias for `int` type.<jupyter_code>module type Int = sig
  type t = int
end<jupyter_output><empty_output><jupyter_text>Now we can define the functor as follows:<jupyter_code>module Id (X: Int) : Int = X<jupyter_output><empty_output><jupyter_text>The type says that `Id` is a functor which takes a module of type `Int` and returns another module of the same module type `Int`. We can apply the functor to a module that satisfies this signature as follows:<jupyter_code>module S = Id(struct type t = int let v = 10 end)<jupyter_output><empty_output><jupyter_text>More usefully, with the help of functors we can define a set data structure over arbitrary data type:<jupyter_code>module Set (Content: sig type t end): sig
  type t
  val empty: t
  val mem: Content.t -> t -> bool
  val add: Content.t -> t -> t
end = struct
  type t = Content.t list

  let empty : t = []

  let mem i s =
    let is_i j = (i = j) in
      List.exists is_i s

  let add i s =
    if mem i s then s
    else i :: s
end<jupyter_output><empty_output><jupyter_text>We can use this to create a set of integers:<jupyter_code>module IntSet = Set(struct type t = int end)
let is = IntSet.add 1 (IntSet.add 2 (IntSet.empty))<jupyter_output><empty_output><jupyter_text>or floats:<jupyter_code>module FloatSet = Set(struct type t = float end)
let fs = FloatSet.add 0.1 (FloatSet.add 0.2 (FloatSet.empty))<jupyter_output><empty_output><jupyter_text>or set of set of integers:<jupyter_code>module IntSetSet = Set(IntSet)
let iis = IntSetSet.add is IntSetSet.empty<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08042691061558986, 'fraction_numerical': 0.0026681913474366306, 'mean_word_length': 4.449636552440291, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 61, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '184873', 'license': 'Apache-2.0', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1579, 'n_words': 712, 'path': 'notebooks/Lesson 3 -- Modules.ipynb', 'repo_name': 'kayceesrk/ocaml-tutorial', 'size': '5247'}