deep_causality_haft/algebra/comonad.rs
1/*
2 * SPDX-License-Identifier: MIT
3 * Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4 */
5use crate::{Functor, HKT};
6use deep_causality_num::Zero;
7
8/// The `CoMonad` trait represents a comonadic context, which is the dual of a `Monad`.
9///
10/// While a `Monad` allows for chaining computations that produce values *within* a context
11/// (e.g., `bind` for `M<A>` to `M<B>`), a `CoMonad` focuses on computations that consume
12/// values *from* a context and produce new contexts based on observations.
13///
14/// Think of a `CoMonad` as a context that can be "inspected" or "observed" to yield a value,
15/// and then "extended" to produce new contexts by applying a function that observes the original context.
16///
17/// It provides two primary operations:
18/// - `extract`: To get the current value at the "focus" of the context.
19/// - `extend`: To create a new comonadic context by applying a function that transforms
20/// the original context itself into a value, which then becomes the content of the new context.
21///
22/// # Intuition & Analogy
23///
24/// A common analogy is a spreadsheet cell:
25/// - `extract` gets the value of the current cell.
26/// - `extend` allows you to fill a new spreadsheet with the results of formulas applied
27/// to the original spreadsheet. Each cell in the new spreadsheet is derived by observing
28/// the context of the old spreadsheet (e.g., the cell itself and its neighbors).
29///
30/// # Laws (Informal)
31///
32/// 1. **Left Identity**: `extend(w, extract) = w`
33/// (Extending a context with its own `extract` function should yield the original context).
34/// 2. **Right Identity**: `extract(extend(w, f)) = f(w)`
35/// (Extracting from an extended context should be the same as directly applying the function `f` to the context).
36/// 3. **Associativity**: `extend(extend(w, f), g) = extend(w, |w_prime| g(extend(w_prime, f)))`
37/// (Extending twice is equivalent to extending once with a composed function).
38///
39/// # Type Parameters
40///
41/// * `F`: A Higher-Kinded Type (HKT) witness that represents the type constructor
42/// (e.g., `BoxWitness`). This `F` must also be a `Functor`.
43pub trait CoMonad<F: HKT>: Functor<F> {
44 /// Extracts the value at the current focus of the comonadic context.
45 ///
46 /// This operation allows you to "peek inside" the context and obtain its current value
47 /// without transforming the context itself.
48 ///
49 /// # Arguments
50 ///
51 /// * `fa`: A reference to the comonadic context (`F::Type<A>`).
52 ///
53 /// # Returns
54 ///
55 /// The value `A` contained within the context `fa`.
56 ///
57 /// # Type Parameters
58 ///
59 /// * `A`: The type of the value to extract.
60 ///
61 /// # Requirements
62 ///
63 /// * `A: Clone`: The extracted value must be clonable, as `extract` takes a reference
64 /// and returns an owned value, implying a copy.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use deep_causality_haft::{BoxWitness, CoMonad};
70 ///
71 /// let box_val = Box::new(42);
72 /// let extracted = BoxWitness::extract(&box_val);
73 /// assert_eq!(extracted, 42);
74 /// ```
75 fn extract<A>(fa: &F::Type<A>) -> A
76 where
77 A: Clone;
78
79 /// Extends the comonadic context by applying a function to its observed state.
80 ///
81 /// This creates a new comonadic context `F::Type<B>`, where each element `B` is the
82 /// result of applying the function `f` to the *original* context `fa`.
83 /// The function `f` receives a reference to the `fa` (the original context)
84 /// and should produce a value `B`.
85 ///
86 /// # Arguments
87 ///
88 /// * `fa`: A reference to the original comonadic context (`F::Type<A>`).
89 /// * `f`: A function (`Func`) that takes a reference to the context `F::Type<A>`
90 /// and returns a new value `B`. This function represents an "observation"
91 /// or "computation" based on the current context.
92 ///
93 /// # Returns
94 ///
95 /// A new comonadic context (`F::Type<B>`) where each element is the result
96 /// of applying `f` to the original context.
97 ///
98 /// # Type Parameters
99 ///
100 /// * `A`: The type of the values in the original context.
101 /// * `B`: The type of the values in the new context.
102 /// * `Func`: The type of the extension function, which must be `FnMut(&F::Type<A>) -> B`.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// use deep_causality_haft::{BoxWitness, CoMonad, HKT};
108 ///
109 /// let box_val = Box::new(5);
110 ///
111 /// // Extend to create a new Box containing the square of the original value
112 /// let f_square = |b: &<BoxWitness as HKT>::Type<i32>| (**b) * (**b);
113 /// let extended_square = BoxWitness::extend(&box_val, f_square);
114 /// assert_eq!(extended_square, Box::new(25));
115 ///
116 /// // Extend to create a new Box containing a string representation
117 /// let f_to_string = |b: &<BoxWitness as HKT>::Type<i32>| format!("Value: {}", **b);
118 /// let extended_string = BoxWitness::extend(&box_val, f_to_string);
119 /// assert_eq!(extended_string, Box::new("Value: 5".to_string()));
120 /// ```
121 fn extend<A, B, Func>(fa: &F::Type<A>, f: Func) -> F::Type<B>
122 where
123 Func: FnMut(&F::Type<A>) -> B;
124}
125
126/// A Comonad that requires its contents to satisfy algebraic bounds.
127/// Essential for structures like MultiVectors that need a 'Zero' to represent
128/// a Physical Field Operator.
129pub trait BoundedComonad<F: HKT>: Functor<F> {
130 fn extract<A>(fa: &F::Type<A>) -> A
131 where
132 A: Clone; // Extract usually requires Clone
133
134 fn extend<A, B, Func>(fa: &F::Type<A>, f: Func) -> F::Type<B>
135 where
136 Func: FnMut(&F::Type<A>) -> B,
137 A: Zero + Copy + Clone,
138 B: Zero + Copy + Clone;
139}