Module Preface

The library is divided into 5 parts (in the user area) which serve complementary purposes.

Preface.Specs Contains all the interfaces of the available abstractions. The specifications resemble the _intf suffixed signatures found in other libraries in the OCaml ecosystem.
Preface.Make Contains the set of functors (in the ML sense of the term) for concretising abstractions. Schematically, a module in Preface.Make takes a module (or modules) respecting a signature described in Preface.Specs to produce a complete signature (also described in Preface.Specs).
Preface.Laws Functors to generate laws for a given abstraction.
Preface Contains concrete implementations, constructs that implement abstractions described in Preface.Specs by means of the functors present in Preface.Make. This library is, at least, an example of the use of Specs and Make.

Abstraction implementations

Functor (in Haskell sense), Applicatives and monads are some of the best known abstractions in functional programming. Indeed, they allow recurrent problems to be solved in an elegant way. Generally, thanks to certain mechanisms linked to the languages that implement them (in Haskell, for example, using typeclasses), it is possible, by defining only a small subset of their combinators, to derive many others. So the purpose of "this part of the library" is to provide mechanisms for deriving combinators for a given type and a chosen abstraction, respecting OCaml programming idioms as much as possible.

Specifications

This module describes the specifications of the abstractions provided by Preface. These specifications, which correspond to interfaces (module types in OCaml terminology) serve as constraints for the functors described in Preface.Make and centralise the documentation. Using a separate module allows cyclic dependencies to be resolved if one module can be described by another module and vice versa.

module Specs = Preface_specs

Achievements

In order to produce embodiments for the abstractions described in Preface.Specs, Preface.Make offers a collection of functors that take modules constrained by the interfaces described in Preface.Specs to produce modules that respect the more complete interfaces also described in Preface.Specs.

module Make = Preface_make

Concepts, Naming and Terminology

The modular design of Preface may seem a little intimidating at first glance. Let's look at the logic of the cut to understand how best to use it to describe new achievements of abstractions.

Abstractions must respect a minimum interface, however, sometimes there are several paths to describe the abstraction. For example, building a Monad on a type requires a return (or pure depending on the convention in practice) and:

In addition, on the basis of these minimum combinators, it is possible to derive other combinators. However, it happens that these combinators are not implemented in an optimal way (this is the cost of abstraction). In the OCaml ecosystem, the use of polymorphic variants is sometimes used to give the user the freedom to implement, or not, a function by wrapping the function definition in a value of this type:

val f : [< `Derived | `Custom of 'a -> 'b ]

Instead of relying on this kind of (rather clever!) trick, we decided to rely mainly on the module language.

To make it easy to describe the embodiment of an abstraction, but still allow for the possibility of providing more efficient implementations (that propagate new implementations on aliases, such as infix operators, or functions that use these functions), Preface proposes a rather particular cut.

Each abstraction is broken down into several sub-modules:

Core This module describes all the fundamental operations. For example, for a monad, we would find return, map, bind, join and compose_left_to_right
Operation The module contains the set of operations that can be described using the Core functions.
Infix The module contains infix operators built on top of the Core and Operation.
Syntax The module contains the let operators (such as let* and let+ for example), built with the Core and Operation functions.

Sometimes it happens that some modules are not present (e.g. when there are no infix operators) or sometimes some additional modules are added, but in general the documentation is clear enough.

The functors exposed in Preface.Make allow you to build each component one by one (Core, Operation, using Core, and Infix and Syntax using Core and Operation) and then group all these modules together to form the abstraction. Or use the Happy Path, which generally offers a similar approach to functors which builds Core but builds the whole abstraction.

Module cutting

Although it is likely that the use of the Happy Path covers a very large part of the use cases and that it is not necessary to achieve every abstraction by hand, it is still possible to do so.

In addition, it is sometimes possible to describe one abstraction by specialising another. In general, these specialisations follow this naming convention: From_name (More_general_module) or To_name (Less_general_module) and sometimes you can build a module on top of another, for example Selective on top of Applicative and the naming follows this convention: Over_name (Req), ie: Selective.Over_applicative.

Standard library

Whereas the previous section dealt mainly with the achievements of abstractions (using functor machinery). This section documents the standard Preface library. A collection of already implemented abstractions for relatively common data structures.

Common datatypes

module Void = Preface_stdlib.Void
module Identity = Preface_stdlib.Identity
module Option = Preface_stdlib.Option
module Either = Preface_stdlib.Either
module Pair = Preface_stdlib.Pair

Collection

module List = Preface_stdlib.List
module Nonempty_list = Preface_stdlib.Nonempty_list
module Seq = Preface_stdlib.Seq
module Stream = Preface_stdlib.Stream

Error handling

module Exn = Preface_stdlib.Exn
module Result = Preface_stdlib.Result
module Validation = Preface_stdlib.Validation
module Try = Preface_stdlib.Try
module Validate = Preface_stdlib.Validate

Functions

module Fun = Preface_stdlib.Fun
module Predicate = Preface_stdlib.Predicate
module Equivalence = Preface_stdlib.Equivalence
module Continuation = Preface_stdlib.Continuation

Transformers over identity

There are some (monad or comonad) transformers defined in Spec/Make. In Stdlib these are some concretised version using Identity as inner monad or comonad.

module Reader = Preface_stdlib.Reader
module Writer = Preface_stdlib.Writer
module State = Preface_stdlib.State
module Store = Preface_stdlib.Store
module Env = Preface_stdlib.Env
module Traced = Preface_stdlib.Traced

Static Analysis

Applicatives, Selectives, Profunctors and Arrows allow, contrary to monads, to perform static analyses on calculation workflows. Over and Under allow optimistic or pessimistic approximations.

module Approximation = Preface_stdlib.Approximation

Laws

Many of the abstractions presented in Preface are governed by laws, to ensure the proper functioning of other derived operations. This library provides functors to generate implemented laws for a concretization of an abstraction.

module Laws = Preface_laws
module Qcheck = Preface_qcheck