{"id":13726124,"url":"https://github.com/xvw/preface","last_synced_at":"2025-04-06T09:06:02.429Z","repository":{"id":39801869,"uuid":"203825924","full_name":"xvw/preface","owner":"xvw","description":"Preface is an opinionated library designed to facilitate the handling of recurring functional programming idioms in OCaml.","archived":false,"fork":false,"pushed_at":"2025-03-04T10:04:32.000Z","size":1230,"stargazers_count":148,"open_issues_count":10,"forks_count":6,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-29T14:44:48.140Z","etag":null,"topics":["category-theory","functional-programming","ocaml","stdlib"],"latest_commit_sha":null,"homepage":"https://ocaml-preface.github.io/preface/index.html","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xvw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-08-22T15:45:47.000Z","updated_at":"2025-03-04T10:04:35.000Z","dependencies_parsed_at":"2024-01-10T18:34:54.029Z","dependency_job_id":null,"html_url":"https://github.com/xvw/preface","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvw%2Fpreface","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvw%2Fpreface/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvw%2Fpreface/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvw%2Fpreface/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xvw","download_url":"https://codeload.github.com/xvw/preface/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457799,"owners_count":20941906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["category-theory","functional-programming","ocaml","stdlib"],"created_at":"2024-08-03T01:02:53.294Z","updated_at":"2025-04-06T09:06:02.422Z","avatar_url":"https://github.com/xvw.png","language":"OCaml","funding_links":[],"categories":["OCaml"],"sub_categories":[],"readme":"# Preface\n\n\u003e Preface is an opinionated library designed to facilitate the\n\u003e handling of recurring functional programming idioms in\n\u003e [OCaml](https://ocaml.org). Many of the design decisions were made\n\u003e in an attempt to calibrate, as best as possible, to the OCaml\n\u003e language. Trying to get the most out of the module language. _The\n\u003e name \"preface\" is a nod to \"Prelude\"_.\n\nWhen learning functional programming, one is often confronted with\nconstructs derived (or not) from category theory. Languages such as\nHaskell offer very complete libraries to use them, and thus,\nfacilitate their learning. In OCaml, it often happens that these\nabstractions are buried in the heart of certain libraries/projects\n([Lwt](https://ocsigen.org/lwt/latest/manual/manual),\n[Cmdliner](https://erratique.ch/logiciel/cmdliner),\n[Bonsai](https://github.com/janestreet/bonsai),\n[Dune](https://dune.build) etc.). This is why one of the objectives of\nPreface is to propose tools for concretising these abstractions, at\nleast as a pedagogical tool.\n\n### Is Preface useful\n\nSince OCaml allows for efficient imperative programming, Preface is\nprobably not really useful for building software. However, we (the\nmaintainers) think that Preface can be useful for a few things:\n\n- technical experimentation with abstractions (especially those from\n  the Haskell world) that allow programming in a fun style.\n- As an educational tool. Many teaching aids generally only offer the\n  minimal interfaces to these abstractions. Preface tries to be as\n  complete as possible.\n- It was a lot of fun to make. The last point is obviously the\n  lightest but building Preface was really fun! So even if some people\n  won't see the point... **we had fun making it**!\n\n## Installation\n\nThe package is available on OPAM, `opam install preface` should be enough. (And\nby describing, of course, OPAM in your project OPAM file and linking it to your\nproject in the standard way proposed by your build-system.)\n\n### OPAM pin\n\nIf you would like to use the latest version of Preface (under development) you\ncan use the [pin mechanism](https://opam.ocaml.org/doc/Usage.html#opam-pin).\n\n```\n...\ndepends: [\n  ...\n  \"preface\" {pinned}\n]\n\npin-depends: [\n  [\"preface.dev\" \"git+ssh://git@github.com/xvw/preface.git\"]\n  ...\n]\n...\n```\n\n### Esy resolution\n\nThe library can also be installed with [esy](esy.sh) using a resolution in your `package.json` file :\n\n```json\n...\n    \"dependencies\": {\n      ...\n      \"@opam/preface\":\"*\"\n    },\n    \"resolutions\": {\n        \"@opam/preface\":\"xvw/preface#\u003ccommit\u003e\"\n    },\n...\n```\n\nThe pattern of the resolution is `xvw/preface#\u003ccommit\u003e` where `\u003ccommit\u003e` is mandatory and [should point to a specific commit](https://esy.sh/docs/en/using-repo-sources-workflow.html#with-esy-packages).\n\n## Library anatomy\n\nThe library is divided into four parts (in the user area) which serve\ncomplementary purposes.\n\n| Library          | Description                                                                                                                                                                                                                                                                                |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `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.                                                                                                                    |\n| `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`). |\n| `preface.stdlib` | 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`.                                                         |\n| `preface`        | Packs all libraries making `Preface.Specs` and `Preface.Make` accessible as soon as Preface is available in the current scope. And includes `Preface.Stdlib` (so everything in `Preface.Stdlib` is available from Preface).                                                                |\n\n## Available abstractions in `Make` and `Specs`\n\nAlthough `Stdlib` offers common and, in our view, useful\nimplementations, the heart of Preface lies in its ability to build the\nconcretisation of abstractions for all sorts of data structures. Here\nis a list of abstractions that can be built relatively easily. As you\ncan see, the diagram is heavily inspired by the\n[Haskell](https://haskell.org) community's\n[Typeclassopedia](https://wiki.haskell.org/Typeclassopedia).\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://ocaml-preface.github.io/images/specs.svg\" alt=\"typeclassopedia\"\u003e\u003c/p\u003e\n\nObviously, the set of useful abstractions is still far from being present in\nPreface. We have decided to privilege those for which we had a short and medium\nterm use. But if you find that an abstraction is missing, the development of\nPreface is open, don't hesitate to contribute by adding what was missing.\n\n## Concretisation in `Stdlib`\n\nAs for the implemented abstractions, we favoured objects that we often\nmanipulated (that we constantly reproduced in our projects) and also\nthose that allowed us to test certain abstractions (`Predicate` and\n`Contravariant` for example). Don't hesitate to add some that would be\nuseful for the greatest number of people!\n\n| Name                  | Description                                                                       | Abstractions                                                                                                                                                                                         |\n| --------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `Approximation.Over`  | A generalization of `Const` (the phantom monoid) for over approximation           | `Applicative`, `Selective`                                                                                                                                                                           |\n| `Approximation.Under` | Same of `Over` but for under approximation                                        | `Applicative`, `Selective`                                                                                                                                                                           |\n| `Continuation`        | A continuation that can't be delimited                                            | `Functor` (and `Invariant`), `Applicative`, `Monad`                                                                                                                                                  |\n| `Env`                 | The env comonad using `Identity`as inner monad                                    | `Functor` (and `Invariant`), `Comonad`                                                                                                                                                               |\n| `Either`              | Represent a disjunction between `left` and `right`                                | `Bifunctor` and can be specialised for the `left` part; `Functor` (and `Invariant`), `Alt`, `Applicative`, `Monad`, `Traversable` through Applicative and Monad, `Foldable`                          |\n| `Equivalence`         | A generalization of function `'a -\u003e 'a -\u003e bool`                                   | `Contravariant` (and `Invariant`), `Divisible`, `Decidable`                                                                                                                                          |\n| `Fun`                 | Function `'a -\u003e 'b`                                                               | `Profunctor`, `Strong`, `Choice`, `Closed`, `Semigroupoid`, `Category`, `Arrow`, `Arrow_choice`, `Arrow_apply`                                                                                       |\n| `Identity`            | A trivial type constructor, `type 'a t = 'a`                                      | `Functor` (and `Invariant`), `Applicative`, `Selective`, `Monad`, `Comonad`                                                                                                                          |\n| `List`                | The standard list of OCaml                                                        | `Foldable`, `Functor` (and `Invariant`), `Applicative`, `Alternative`, `Selective`, `Monad`, `Monad_plus`, `Traversable` through Applicative or Monad, `Monoid` (where the inner type must be fixed) |\n| `Nonempty_list`       | A list with, at least, one element                                                | `Foldable`, `Functor` (and `Invariant`), `Alt`, `Applicative`, `Selective`, `Monad`, `Comonad`, `Traversable` through Applicative or Monad, `Semigroup` (where the inner type must be fixed)         |\n| `Option`              | Deal with absence of values                                                       | `Foldable`, `Functor` (and `Invariant`), `Applicative`, `Alternative`, `Monad`, `Monad_plus`, `Traversable` through Applicative of Monad, `Monoid` (where the inner type must be fixed)              |\n| `Predicate`           | A generalization of function `'a -\u003e bool`                                         | `Contravariant` (and `Invariant`), `Divisible`, `Decidable`                                                                                                                                          |\n| `Reader`              | The reader monad using `Identity` as inner monad                                  | `Functor` (and `Invariant`), `Applicative`, `Monad`                                                                                                                                                  |\n| `Result`              | Deal with `Ok` or `Error` values                                                  | `Bifunctor` and can be specialised for the `error` part; `Functor` (and `Invariant`), `Alt`, `Applicative`, `Monad`, `Traversable` through Applicative and Monad, `Foldable`                         |\n| `Seq`                 | The standard sequence of OCaml                                                    | `Foldable`, `Functor` (and `Invariant`), `Applicative`, `Alternative`, `Selective`, `Monad`, `Monad_plus`, `Traversable` through Applicative or Monad, `Monoid` (where the inner type must be fixed) |\n| `State`               | The state monad using `Identity` as inner monad                                   | `Functor` (and `Invariant`), `Applicative`, `Monad`                                                                                                                                                  |\n| `Store`               | The store comonad using `Identity`as inner monad                                  | `Functor` (and `Invariant`), `Comonad`                                                                                                                                                               |\n| `Stream`              | Infinite list                                                                     | `Functor` (and `Invariant`), `Applicative`, `Monad`, `Comonad`                                                                                                                                       |\n| `Traced`              | The traced comonad using `Identity`as inner monad                                 | `Functor` (and `Invariant`), `Comonad`                                                                                                                                                               |\n| `Try`                 | A biased version of `Result` with `exception` as the error part                   | `Functor` (and `Invariant`), `Alt`, `Applicative`, `Monad`, `Traversable` through Applicative and Monad, `Foldable`                                                                                  |\n| `Pair`                | A pair `'a * 'b`                                                                  | `Bifunctor`                                                                                                                                                                                          |\n| `Validate`            | A biased version of `Validation` with `exception Nonempty_list` as `invalid` part | `Functor` (and `Invariant`), `Alt`, `Applicative`, `Selective`, `Monad`, `Traversable` through Applicative and Monad, `Foldable`                                                                     |\n| `Validation`          | Like `Result` but the `invalid` part is a `Semigroup` for accumulating errors     | `Bifunctor` and can be specialized on the `invalid` part: `Functor` (and `Invariant`), `Alt`, `Applicative`, `Selective`, `Monad`, `Traversable` through Applicative and Monad, `Foldable`           |\n| `Writer`              | The writer monad using `Identity` as inner monad                                  | `Functor` (and `Invariant`), `Applicative`, `Monad`                                                                                                                                                  |\n\n### Stdlib convention\n\nAs it is possible to take several paths to realise an abstraction, we\ndecided to describe each abstraction in a dedicated sub-module. For\nexample `Option.Functor` or `Option.Monad` to let the user choose\nwhich combinators to use.\n\n#### Do not shadow the standard library\n\nAlthough it was tempting to extend the standard OCaml library with\nthis technique:\n\n```ocaml\nmodule Preface : sig\n  module List : sig\n    include module type of List\n    include module type of Preface_stdlib.List\n  end\nend\n```\n\nWe have decided not to do this to ensure consistent documentation (not\nvarying according to the version of OCaml one is using).\n\n## Some design choices\n\nAbstractions must respect a minimum interface, however, sometimes\nthere are several paths to describe the abstraction. For example,\nbuilding a monad on a type requires a `return` (or `pure` depending on\nthe convention in practice) and:\n\n- `bind` (`\u003e\u003e=`)\n- `map` and `join`\n- or possibly `\u003e=\u003e`\n\nIn addition, on the basis of these minimum combinators, it is possible\nto derive other combinators. However, it happens that these\ncombinators are not implemented in an optimal way (this is the cost of\nabstraction). In the OCaml ecosystem, the use of polymorphic variants\nis sometimes used to give the user the freedom to implement, or not, a\nfunction by wrapping the function definition in a value of this type:\n\n```ocaml\nval f : [\u003c `Derived | `Custom of ('a -\u003e 'b)]\n```\n\nInstead of relying on this kind of (rather clever!) trick, we decided\nto rely mainly on the module language.\n\nTo make it easy to describe the embodiment of an abstraction, but\nstill allow for the possibility of providing more efficient\nimplementations (that propagate new implementations on aliases, such\nas infix operators, or functions that use these functions), Preface\nproposes a rather particular cut.\n\nEach abstraction is broken down into several sub-modules:\n\n| Submodule   | Role                                                                                                                                                      |\n| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `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` |\n| `Operation` | The module contains the set of operations that can be described using the `Core` functions.                                                               |\n| `Infix`     | The module contains infix operators built on top of the `Core` and `Operation`.                                                                           |\n| `Syntax`    | The module contains the `let` operators (such as `let*` and `let+` for example), built with the `Core` and `Operation` functions.                         |\n\n\u003e Sometimes it happens that some modules are not present (e.g. when\n\u003e there are no infix operators) or sometimes some additional modules\n\u003e are added, but in general the documentation is clear enough.\n\nThe functors exposed in `Make` allow you to build each component one\nby one (`Core`, `Operation`, using `Core`, and `Infix` and `Syntax`\nusing `Core` and `Operation`) and then group all these modules\ntogether to form the abstraction. Or use the Happy Path, which\ngenerally offers a similar approach to functors which builds `Core`\nbut builds the whole abstraction.\n\nHere is an example of the canonical flow of concretisation of an\nabstraction:\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://ocaml-preface.github.io/images/cut.svg\" alt=\"module hierarchy\"\u003e\u003c/p\u003e\n\nAlthough it is likely that the use of the _Happy Path_ covers a very\nlarge part of the use cases and that it is not necessary to concretise\nevery abstraction by hand, it is still possible to do so.\n\nIn addition, it is sometimes possible to describe one abstraction by\nspecialising another. In general, these specialisations follow this\nnaming convention: `From_name (More_general_module)` or `To_name (Less_general_module)` and sometimes you can build a module on top of\nanother, for example `Selective` on top of `Applicative` and the\nnaming follows this convention: `Over_name (Req)`, ie\n`Selective.Over_applicative`\n\n## Projects using Preface\n\n| Project name | Description                                                                                                                  | Links                                                      |\n| ------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |\n| **YOCaml**   | YOCaml is a static blog generator that essentially takes advantage of Preface's `Freer`, `Result`, `Validation` and `Arrow`. | [Github repository](https://github.com/xhtmlboi/yocaml)    |\n| **Muhokama** | A simple forum built on top of Dream, Caqti, Omd, Preface, Cmdliner and other useful OCaml libraries                         | [Github repository](https://github.com/xvw/muhokama)       |\n| **Jaylang**  | A semantically typed language that uses Preface for abstractions including `Arrow`, `Writer`, `Nonempty_list`, and more.     | [Github repository](https://github.com/JHU-PL-Lab/jaylang) |\n\nYou use Preface for one of your projects and you want to be in this\nlist? Don't hesitate to open a PR or fill an issue, we'd love to hear\nfrom you.\n\n## closing remarks\n\nPreface is a fun project to develop and we have learned a lot from\nit. We hope you find it useful and/or enjoyable to use. We are open to\nany improvements and open to external contributions!\n\nWe received a lot of help during the development of Preface. Feel free\nto go to the [CREDITS](CREDITS.md) page to learn more.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvw%2Fpreface","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxvw%2Fpreface","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvw%2Fpreface/lists"}