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::*;