Module PrefaceSource
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.
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.
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:
bind/>>=- or
map and join - or sometimes
>=>
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.
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
Collection
Error handling
Functions
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.
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.
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.