Skip to main content

fp_library/classes/
comonad.rs

1//! Comonads, the dual of monads, combining [`Extend`] and [`Extract`](crate::classes::Extract).
2//!
3//! A `Comonad` is a type that supports both extracting a value from a context
4//! ([`Extract`](crate::classes::Extract)) and extending a local computation to the whole context
5//! ([`Extend`]). It is the categorical dual of [`Monad`](crate::classes::Monad):
6//! where `Monad` composes `Pointed` + `Semimonad`, `Comonad` composes
7//! `Extract` + `Extend`.
8//!
9//! This module is a port of PureScript's
10//! [`Control.Comonad`](https://pursuit.purescript.org/packages/purescript-control/docs/Control.Comonad).
11//!
12//! # Hierarchy
13//!
14//! ```text
15//! Functor
16//!   |
17//!   +-- Extract              (extract :: F<A> -> A; no Functor constraint)
18//!   |
19//!   +-- Extend: Functor      (extend :: (F<A> -> B) -> F<A> -> F<B>)
20//!   |
21//!   +-- Comonad: Extend + Extract   (blanket impl, no new methods)
22//! ```
23
24#[fp_macros::document_module(no_validation)]
25mod inner {
26	use crate::classes::*;
27
28	/// A type class for comonads, combining [`Extend`] and [`Extract`].
29	///
30	/// `class (Extend w, Extract w) => Comonad w`
31	///
32	/// `Comonad` is the dual of [`Monad`](crate::classes::Monad). Where a `Monad`
33	/// lets you sequence effectful computations by injecting values (`pure`) and
34	/// chaining with `bind`, a `Comonad` lets you observe values (`extract`) and
35	/// extend local computations to global ones (`extend`).
36	///
37	/// # Laws
38	///
39	/// A lawful `Comonad` must satisfy three laws:
40	///
41	/// 1. **Left identity:** extracting after extending recovers the function's
42	///    result.
43	///
44	///    ```text
45	///    extract(extend(f, wa)) == f(wa)
46	///    ```
47	///
48	/// 2. **Right identity:** extending with `extract` is a no-op.
49	///
50	///    ```text
51	///    extend(extract, wa) == wa
52	///    ```
53	///
54	/// 3. **Map-extract:** extracting after mapping is the same as applying the
55	///    function to the extracted value.
56	///
57	///    ```text
58	///    extract(map(f, wa)) == f(extract(wa))
59	///    ```
60	pub trait Comonad: Extend + Extract {}
61
62	/// Blanket implementation of [`Comonad`].
63	#[document_type_parameters("The brand type.")]
64	impl<Brand> Comonad for Brand where Brand: Extend + Extract {}
65}
66
67pub use inner::*;