deep_causality_haft/hkt/
mod.rs

1/*
2 * SPDX-License-Identifier: MIT
3 * Copyright (c) 2023 - 2026. The DeepCausality Authors and Contributors. All Rights Reserved.
4 */
5
6//! Core Higher-Kinded Type (HKT) Machinery.
7//!
8//! This module provides the foundational traits and types required to emulate Higher-Kinded Types (HKTs)
9//! in Rust, a language that does not natively support them. It uses the "Generic Associated Types (GAT) Pattern"
10//! to achieve this.
11//!
12//! # The Problem: Missing HKTs in Rust
13//!
14//! In languages like Haskell, you can write a trait (typeclass) that is generic over a type constructor `F<_>`:
15//!
16//! ```haskell
17//! class Functor f where
18//!   fmap :: (a -> b) -> f a -> f b
19//! ```
20//!
21//! In Rust, generic parameters must be concrete types (of kind `*`), not type constructors (of kind `* -> *`).
22//! You cannot write `trait Functor<F<A>>`.
23//!
24//! # The Solution: The GAT Pattern
25//!
26//! We define a "Witness" trait (`HKT`) that acts as a proxy for the type constructor. This witness trait
27//! contains a Generic Associated Type (GAT) `Type<T>` which projects the witness back to the concrete type.
28//!
29//! ```rust,ignore
30//! pub trait HKT {
31//!     type Type<T>; // The GAT
32//! }
33//!
34//! struct OptionWitness; // The Witness
35//! impl HKT for OptionWitness {
36//!     type Type<T> = Option<T>; // The Projection
37//! }
38//! ```
39//!
40//! This allows us to write generic traits like `Functor` over the witness `F`:
41//!
42//! ```rust,ignore
43//! trait Functor<F: HKT> {
44//!     fn fmap<A, B>(fa: F::Type<A>, f: Fn(A) -> B) -> F::Type<B>;
45//! }
46//! ```
47//!
48//! # Module Contents
49//!
50//! *   [`hkt`]: Defines the standard `HKT` trait (Arity 1) and fixed-parameter HKTs (`HKT2`, `HKT3`, etc.)
51//!     where all but one parameter are fixed.
52//! *   [`hkt_unbound`]: Defines "Unbound" HKT traits (`HKT2Unbound`, `HKT3Unbound`, etc.) where
53//!     multiple parameters remain generic. This corresponds to multi-parameter type constructors
54//!     like `Result<E, T>` (Bifunctor) or `(A, B, C)` (Trifunctor).
55//!
56//! # Arity Support
57//!
58//! This crate supports HKTs up to Arity 6 (for complex effect systems).
59//!
60//! *   **Arity 1**: `HKT` (e.g., `Option<T>`, `Vec<T>`)
61//! *   **Arity 2**: `HKT2` (Fixed), `HKT2Unbound` (e.g., `Result<E, T>`)
62//! *   **Arity 3**: `HKT3` (Fixed), `HKT3Unbound` (e.g., `(A, B, C)`)
63//! *   **Arity 4**: `HKT4` (Fixed), `HKT4Unbound`
64//! *   **Arity 5**: `HKT5` (Fixed), `HKT5Unbound`
65//! *   **Arity 6**: `HKT6Unbound`
66
67/// Marker trait indicating that type `T` satisfies constraint `C`.
68///
69/// This is the core abstraction that enables type-safe constraint checking
70/// at compile time. Constraints are implemented as marker structs, and
71/// blanket implementations of `Satisfies` define which types satisfy each constraint.
72///
73/// # Design Philosophy
74///
75/// The `?Sized` bound on `C` allows for flexibility in constraint definitions,
76/// including trait objects if needed in the future.
77///
78/// # Safety
79///
80/// This trait is a pure marker and has no methods. Implementations should
81/// not have any runtime behavior.
82pub trait Satisfies<C: ?Sized> {}
83
84/// The universal constraint — every type satisfies it.
85///
86/// Use this constraint for fully polymorphic HKT implementations like
87/// `Vec`, `Option`, `Box`, etc., where no specific bounds are required
88/// on the inner type.
89///
90/// # Example
91///
92/// ```rust
93/// use deep_causality_haft::{Satisfies, NoConstraint};
94///
95/// // This blanket impl means String, Vec<u8>, custom types, etc. all satisfy NoConstraint
96/// fn accepts_any<T: Satisfies<NoConstraint>>(_: T) {}
97///
98/// accepts_any("hello");
99/// accepts_any(42);
100/// accepts_any(vec![1, 2, 3]);
101/// ```
102pub struct NoConstraint;
103
104impl<T> Satisfies<NoConstraint> for T {}
105
106// ----------------------------------------------------
107// Higher Kinded Types (HKT) Traits for Arity 1 - 5
108// ----------------------------------------------------
109
110/// A zero-sized type used purely as a marker or placeholder when implementing
111/// Higher-Kinded Type (HKT) traits for concrete types.
112///
113/// This struct is essential for the "witness" pattern, where a concrete type
114/// (like `Option<T>`) cannot directly implement an HKT trait due to Rust's
115/// type system limitations. Instead, a `Witness` type (e.g., `OptionWitness`)
116/// implements the HKT trait, using `Placeholder` to represent the generic
117/// parameters that are being abstracted over.
118///
119/// # Examples
120///
121/// ```
122/// use deep_causality_haft::{NoConstraint, HKT, Placeholder};
123///
124/// // A witness for Option<T>
125/// pub struct OptionWitness;
126///
127/// impl HKT for OptionWitness {
128///     type Constraint = NoConstraint;
129///     type Type<T> = Option<T>;
130/// }
131///
132/// let my_option: <OptionWitness as HKT>::Type<i32> = Some(10);
133/// assert_eq!(my_option, Some(10));
134/// ```
135pub struct Placeholder;
136
137/// Trait for a Higher-Kinded Type (HKT) with one type parameter (arity 1).
138///
139/// This trait is implemented by a concrete "witness" type (e.g., `OptionWitness`)
140/// which serves as a token to refer to a type constructor (e.g., `Option<T>`).
141/// The `Type<T>` associated type defines the actual type constructor, with `<T>`
142/// representing the single generic parameter that can vary.
143///
144/// # Unified Constraint System
145///
146/// The `Constraint` associated type declares what bounds the inner type `T` must satisfy
147/// when using functional operations like `fmap`, `bind`, etc. This enables a **single
148/// trait hierarchy** for both constrained and unconstrained types:
149///
150/// - **Unconstrained types** (like `Vec<T>`) use `type Constraint = NoConstraint;`
151/// - **Constrained types** (like `CausalTensor<T>`) use `type Constraint = TensorDataConstraint;`
152///
153/// Note: The constraint is enforced at the trait method level (Functor, Monad, etc.),
154/// not at the `Type<T>` GAT level. This allows the GAT to be used with any type,
155/// while the functional operations validate the constraints.
156///
157/// # For Unconstrained Types
158///
159/// ```rust
160/// use deep_causality_haft::{HKT, NoConstraint};
161///
162/// pub struct VecWitness;
163///
164/// impl HKT for VecWitness {
165///     type Constraint = NoConstraint;
166///     type Type<T> = Vec<T>;
167/// }
168/// ```
169///
170/// # For Constrained Types
171///
172/// ```rust,ignore
173/// impl HKT for CausalTensorWitness {
174///     type Constraint = TensorDataConstraint;
175///     type Type<T> = CausalTensor<T>;
176/// }
177/// ```
178///
179/// # Type Parameters
180///
181/// *   `T`: The generic type parameter that the type constructor operates on.
182pub trait HKT {
183    /// The constraint on inner types. Use `NoConstraint` for fully polymorphic.
184    type Constraint: ?Sized;
185
186    /// The Generic Associated Type (GAT) that represents the type constructor.
187    /// The `<T>` is the "hole" in the type constructor (e.g., `Option<T>`).
188    ///
189    /// The where clause ensures constraint propagation at the type level,
190    /// enabling types with inherent bounds (like `CausalMultiField`) to
191    /// participate in the unified HKT system.
192    type Type<T>
193    where
194        T: Satisfies<Self::Constraint>;
195}
196
197// ----------------------------------------------------
198// HKT Trait for Arity 2: Kind *, * -> *
199// ----------------------------------------------------
200
201/// Trait for a Higher-Kinded Type (HKT) with two type parameters (arity 2).
202///
203/// This trait is generic over the first type parameter to be "fixed" (`F`).
204/// This allows the trait to represent a type constructor that is partially applied,
205/// leaving one generic parameter (`T`) open.
206///
207/// # Purpose
208///
209/// Useful for type constructors like `Result<T, E>` where `E` (the error type)
210/// can be fixed, allowing the `Result` to behave like an arity-1 HKT over `T`.
211/// This is crucial for integrating such types into functional programming patterns
212/// where only one type parameter is expected to vary.
213///
214/// # Type Parameters
215///
216/// *   `F`: The first generic type parameter that is fixed by the implementing witness.
217/// *   `T`: The remaining generic type parameter that the type constructor operates on.
218///
219/// # Examples
220///
221/// ```
222/// use deep_causality_haft::{HKT2, Placeholder};
223///
224/// // A witness for Result<T, E> where E is fixed
225/// pub struct ResultWitness<E>(Placeholder, E);
226///
227/// impl<E> HKT2<E> for ResultWitness<E> {
228///     type Type<T> = Result<T, E>;
229/// }
230///
231/// type MyResult<T> = <ResultWitness<String> as HKT2<String>>::Type<T>;
232/// let ok_value: MyResult<i32> = Ok(20);
233/// assert_eq!(ok_value, Ok(20));
234/// ```
235pub trait HKT2<F> {
236    /// The GAT that represents the remaining type constructor.
237    /// The resulting kind is `* -> *` (one hole `<T>` remaining).
238    ///
239    /// Example: If the implementing type is `Result<(), F>` and `F` is `i32`,
240    /// then `Type<T>` is `Result<T, i32>`.
241    type Type<T>;
242}
243
244// ----------------------------------------------------
245// HKT Trait for Arity 3: Kind *, *, * -> *
246// ----------------------------------------------------
247
248/// Trait for a Higher-Kinded Type (HKT) with three type parameters (arity 3).
249///
250/// This trait is generic over the first two type parameters to be "fixed" (`F1` and `F2`).
251/// This allows the trait to represent a type constructor that is partially applied,
252/// leaving one generic parameter (`T`) open.
253///
254/// # Purpose
255///
256/// Essential for building type-encoded effect systems where two specific effect types
257/// (e.g., Error and Warning/Log) are fixed, and the primary value type `T` remains generic.
258/// This enables explicit tracking of multiple side-effects within a single type.
259///
260/// # Type Parameters
261///
262/// *   `F1`: The first generic type parameter that is fixed (e.g., an Error type).
263/// *   `F2`: The second generic type parameter that is fixed (e.g., a Warning/Log type).
264/// *   `T`: The remaining generic type parameter that the type constructor operates on.
265///
266/// # Examples
267///
268/// ```
269/// use deep_causality_haft::{HKT3, Placeholder};
270///
271/// // A dummy type with three generic parameters
272/// struct MyCustomType<T, F1, F2> { value: T, _f1: F1, _f2: F2, }
273///
274/// // Witness for MyCustomType<T, F1, F2> where F1 and F2 are fixed
275/// struct MyCustomTypeWitness<F1, F2>(Placeholder, F1, F2);
276///
277/// impl<F1, F2> HKT3<F1, F2> for MyCustomTypeWitness<F1, F2> {
278///     type Type<T> = MyCustomType<T, F1, F2>;
279/// }
280///
281/// type MyHkt3Type<T> = <MyCustomTypeWitness<String, u32> as HKT3<String, u32>>::Type<T>;
282/// let instance = MyHkt3Type {
283///     value: 30,
284///     _f1: "Fixed String".to_string(),
285///     _f2: 100u32,
286/// };
287/// assert_eq!(instance.value, 30);
288/// ```
289pub trait HKT3<F1, F2> {
290    /// The GAT that represents the remaining type constructor.
291    /// The resulting kind is `* -> *` (one hole `<T>` remaining).
292    ///
293    /// Example: If the implementing type is `DiscoveryResult<(), F1, F2>`,
294    /// then `Type<T>` is `DiscoveryResult<T, F1, F2>`.
295    type Type<T>;
296}
297
298// ----------------------------------------------------
299// HKT Trait for Arity 4: Kind *, *, *, * -> *
300// ----------------------------------------------------
301
302/// Trait for a Higher-Kinded Type (HKT) with four type parameters (arity 4).
303///
304/// This trait is generic over the first three type parameters to be "fixed" (`F1`, `F2`, `F3`).
305/// This allows the trait to represent a type constructor that is partially applied,
306/// leaving one generic parameter (`T`) open.
307///
308/// # Purpose
309///
310/// Extends the concept of `HKT3` to include a third fixed effect type.
311/// This is useful for more complex effect systems that need to track three distinct
312/// side-effects (e.g., Error, Warning, and a Counter) alongside the primary value type.
313///
314/// # Type Parameters
315///
316/// *   `F1`: The first generic type parameter that is fixed.
317/// *   `F2`: The second generic type parameter that is fixed.
318/// *   `F3`: The third generic type parameter that is fixed.
319/// *   `T`: The remaining generic type parameter that the type constructor operates on.
320///
321/// # Examples
322///
323/// ```
324/// use deep_causality_haft::{HKT4, Placeholder};
325///
326/// // A dummy type with four generic parameters
327/// struct MyCustomType4<T, F1, F2, F3> { value: T, _f1: F1, _f2: F2, _f3: F3, }
328///
329/// // Witness for MyCustomType4<T, F1, F2, F3> where F1, F2, and F3 are fixed
330/// struct MyCustomTypeWitness4<F1, F2, F3>(Placeholder, F1, F2, F3);
331///
332/// impl<F1, F2, F3> HKT4<F1, F2, F3> for MyCustomTypeWitness4<F1, F2, F3> {
333///     type Type<T> = MyCustomType4<T, F1, F2, F3>;
334/// }
335///
336/// type MyHkt4Type<T> =
337///     <MyCustomTypeWitness4<String, u32, bool> as HKT4<String, u32, bool>>::Type<T>;
338///
339/// let instance = MyHkt4Type {
340///     value: 40,
341///     _f1: "Fixed String".to_string(),
342///     _f2: 200u32,
343///     _f3: true,
344/// };
345/// assert_eq!(instance.value, 40);
346/// ```
347pub trait HKT4<F1, F2, F3> {
348    /// The GAT that represents the remaining type constructor.
349    /// The resulting kind is `* -> *` (one hole `<T>` remaining).
350    type Type<T>;
351}
352
353// ----------------------------------------------------
354// HKT Trait for Arity 5: Kind *, *, *, *, * -> *
355// ----------------------------------------------------
356
357/// Trait for a Higher-Kinded Type (HKT) with five type parameters (arity 5).
358///
359/// This trait is generic over the first four type parameters to be "fixed" (`F1`, `F2`, `F3`, `F4`).
360/// This allows the trait to represent a type constructor that is partially applied,
361/// leaving one generic parameter (`T`) open.
362///
363/// # Purpose
364///
365/// Provides the highest arity HKT trait for highly expressive type-encoded effect systems.
366/// It enables tracking four distinct side-effects (e.g., Error, Warning, Counter, and Trace)
367/// alongside the primary value type, offering fine-grained control over computational effects.
368///
369/// # Type Parameters
370///
371/// *   `F1`: The first generic type parameter that is fixed.
372/// *   `F2`: The second generic type parameter that is fixed.
373/// *   `F3`: The third generic type parameter that is fixed.
374/// *   `F4`: The fourth generic type parameter that is fixed.
375/// *   `T`: The remaining generic type parameter that the type constructor operates on.
376///
377/// # Examples
378///
379/// ```
380/// use deep_causality_haft::{HKT5, Placeholder};
381///
382/// // A dummy type with five generic parameters
383/// struct MyCustomType5<T, F1, F2, F3, F4> { value: T, _f1: F1, _f2: F2, _f3: F3, _f4: F4, }
384///
385/// // Witness for MyCustomType5<T, F1, F2, F3, F4> where F1, F2, F3, and F4 are fixed
386/// struct MyCustomTypeWitness5<F1, F2, F3, F4>(Placeholder, F1, F2, F3, F4);
387///
388/// impl<F1, F2, F3, F4> HKT5<F1, F2, F3, F4> for MyCustomTypeWitness5<F1, F2, F3, F4> {
389///     type Type<T> = MyCustomType5<T, F1, F2, F3, F4>;
390/// }
391///
392/// type MyHkt5Type<T> =
393///     <MyCustomTypeWitness5<String, u32, bool, f64> as HKT5<String, u32, bool, f64>>::Type<T>;
394///
395/// let instance = MyHkt5Type {
396///     value: 50,
397///     _f1: "Fixed String".to_string(),
398///     _f2: 300u32,
399///     _f3: false,
400///     _f4: 1.23,
401/// };
402/// assert_eq!(instance.value, 50);
403/// ```
404pub trait HKT5<F1, F2, F3, F4> {
405    /// The GAT that represents the remaining type constructor.
406    /// The resulting kind is `* -> *` (one hole `<T>` remaining).
407    type Type<T>;
408}
409
410// ----------------------------------------------------
411// Unbound Higher Kinded Types (HKT) Traits for Arity 2 - 5
412// ----------------------------------------------------
413
414/// Trait for a Higher-Kinded Type (HKT) with two unbound generic parameters (Arity 2).
415///
416/// Unlike `HKT2`, which fixes one parameter and leaves one free (`F<T>`),
417/// `HKT2Unbound` leaves *both* parameters free (`F<A, B>`).
418///
419/// # Category Theory
420/// Corresponds to a **Bifunctor** or a type constructor $F: \mathcal{C} \times \mathcal{D} \to \mathcal{E}$.
421/// It maps a pair of objects $(A, B)$ to a new object $F(A, B)$.
422///
423/// # Examples
424/// * `Result<A, B>`
425/// * `(A, B)` (Tuple)
426/// * `Either<A, B>`
427pub trait HKT2Unbound {
428    type Constraint: ?Sized;
429    /// The Generic Associated Type representing F<A, B>
430    type Type<A, B>
431    where
432        A: Satisfies<Self::Constraint>,
433        B: Satisfies<Self::Constraint>;
434}
435
436/// Trait for a Higher-Kinded Type (HKT) with three generic parameters (Arity 3).
437///
438/// # Category Theory
439/// Corresponds to a **Trifunctor** or a type constructor $F: \mathcal{C} \times \mathcal{D} \times \mathcal{E} \to \mathcal{S}$.
440///
441/// # Examples
442/// * `(A, B, C)` (Triple)
443/// * `State<S_in, S_out, A>` (Parametric State)
444pub trait HKT3Unbound {
445    type Constraint: ?Sized;
446    type Type<A, B, C>
447    where
448        A: Satisfies<Self::Constraint>,
449        B: Satisfies<Self::Constraint>,
450        C: Satisfies<Self::Constraint>;
451}
452
453/// Trait for a Higher-Kinded Type (HKT) with four generic parameters (Arity 4).
454///
455/// # Category Theory
456/// Corresponds to a **Quadrifunctor** or a generic tensor of rank 4.
457///
458/// # Examples
459/// * `(A, B, C, D)` (Quadruple)
460/// * `RiemannTensor<A, B, C, D>`
461pub trait HKT4Unbound {
462    type Constraint: ?Sized;
463    type Type<A, B, C, D>
464    where
465        A: Satisfies<Self::Constraint>,
466        B: Satisfies<Self::Constraint>,
467        C: Satisfies<Self::Constraint>,
468        D: Satisfies<Self::Constraint>;
469}
470
471/// Trait for a Higher-Kinded Type (HKT) with five generic parameters (Arity 5).
472///
473/// # Category Theory
474/// Corresponds to a **Pentafunctor**.
475///
476/// # Examples
477/// * `(A, B, C, D, E)` (Quintuple)
478/// * `CyberneticLoop<S, B, C, A, E>`
479pub trait HKT5Unbound {
480    type Constraint: ?Sized;
481    type Type<A, B, C, D, E>
482    where
483        A: Satisfies<Self::Constraint>,
484        B: Satisfies<Self::Constraint>,
485        C: Satisfies<Self::Constraint>,
486        D: Satisfies<Self::Constraint>,
487        E: Satisfies<Self::Constraint>;
488}
489
490/// Trait for a Higher-Kinded Type (HKT) with six generic parameters (Arity 6).
491///
492/// # Category Theory
493/// Corresponds to a **Hexafunctor**.
494///
495/// # Examples
496/// * `(A, B, C, D, E, F)` (Sextuple)
497/// * `Effect5Unbound<Fixed1, Fixed2, Fixed3, S_in, S_out, A>`
498pub trait HKT6Unbound {
499    type Constraint: ?Sized;
500    type Type<A, B, C, D, E, F>
501    where
502        A: Satisfies<Self::Constraint>,
503        B: Satisfies<Self::Constraint>,
504        C: Satisfies<Self::Constraint>,
505        D: Satisfies<Self::Constraint>,
506        E: Satisfies<Self::Constraint>,
507        F: Satisfies<Self::Constraint>;
508}