fp_library/brands.rs
1//! Brands represent higher-kinded (unapplied/partially-applied) forms of
2//! [types][crate::types], as opposed to concrete types, which are
3//! fully-applied.
4//!
5//! For example, [`VecBrand`] represents the higher-kinded type [`Vec`], whereas
6//! `Vec A`/`Vec<A>` is the concrete type where `Vec` has been applied to some
7//! generic type `A`.
8//!
9//! ### Examples
10//!
11//! ```
12//! use fp_library::{
13//! brands::*,
14//! functions::*,
15//! };
16//!
17//! let x = Some(5);
18//! let y = map::<OptionBrand, _, _>(|i| i * 2, x);
19//! assert_eq!(y, Some(10));
20//! ```
21
22use {
23 crate::classes::RefCountedPointer,
24 std::marker::PhantomData,
25};
26
27pub mod optics;
28
29/// Brand for [`Arc`](std::sync::Arc) atomic reference-counted pointer.
30#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct ArcBrand;
32
33/// Brand for [atomically reference-counted][std::sync::Arc]
34/// [closures][Fn] (`Arc<dyn Fn(A) -> B>`).
35///
36/// This type alias provides a way to construct and type-check [`Arc`](std::sync::Arc)-wrapped
37/// closures in a generic context.
38pub type ArcFnBrand = FnBrand<ArcBrand>;
39
40/// An adapter that partially applies a `Bifunctor` to its first argument, creating a `Functor` over the second argument.
41///
42/// ### Examples
43///
44/// ```
45/// use fp_library::{
46/// brands::*,
47/// classes::functor::map,
48/// };
49///
50/// let x = Result::<i32, i32>::Ok(5);
51/// let y = map::<BifunctorFirstAppliedBrand<ResultBrand, i32>, _, _>(|s| s * 2, x);
52/// assert_eq!(y, Ok(10));
53/// ```
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
55pub struct BifunctorFirstAppliedBrand<Brand, A>(PhantomData<(Brand, A)>);
56
57/// An adapter that partially applies a `Bifunctor` to its second argument, creating a `Functor` over the first argument.
58///
59/// ### Examples
60///
61/// ```
62/// use fp_library::{
63/// brands::*,
64/// classes::functor::map,
65/// };
66///
67/// let x = Result::<i32, i32>::Err(5);
68/// let y = map::<BifunctorSecondAppliedBrand<ResultBrand, i32>, _, _>(|e| e * 2, x);
69/// assert_eq!(y, Err(10));
70/// ```
71#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
72pub struct BifunctorSecondAppliedBrand<Brand, B>(PhantomData<(Brand, B)>);
73
74/// Brand for [`CatList`](crate::types::CatList).
75#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
76pub struct CatListBrand;
77
78/// Brand for the [`Const`](crate::types::const_val::Const) functor.
79#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub struct ConstBrand<R>(PhantomData<R>);
81
82/// Generic function brand parameterized by reference-counted pointer choice.
83#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
84pub struct FnBrand<PtrBrand: RefCountedPointer>(PhantomData<PtrBrand>);
85
86/// Brand for [`Identity`](crate::types::Identity).
87#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub struct IdentityBrand;
89
90/// Brand for [`Lazy`](crate::types::Lazy).
91#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
92pub struct LazyBrand<Config>(PhantomData<Config>);
93
94/// Brand for [`Option`].
95#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
96pub struct OptionBrand;
97
98/// Brand for [`Pair`](crate::types::Pair).
99#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
100pub struct PairBrand;
101
102/// Brand for the partially-applied form of [`Pair`](crate::types::Pair) with the first value applied.
103#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
104pub struct PairFirstAppliedBrand<First>(PhantomData<First>);
105
106/// Brand for the partially-applied form of [`Pair`](crate::types::Pair) with the second value applied.
107#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct PairSecondAppliedBrand<Second>(PhantomData<Second>);
109
110/// An adapter that partially applies a `Profunctor` to its first argument, creating a `Functor`.
111///
112/// ### Examples
113///
114/// ```
115/// use fp_library::{
116/// brands::*,
117/// classes::functor::map,
118/// };
119///
120/// let f = |x: i32| x + 1;
121/// let g = map::<ProfunctorFirstAppliedBrand<RcFnBrand, i32>, _, _>(
122/// |y: i32| y * 2,
123/// std::rc::Rc::new(f) as std::rc::Rc<dyn Fn(i32) -> i32>,
124/// );
125/// assert_eq!(g(10), 22); // (10 + 1) * 2 = 22
126/// ```
127#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
128pub struct ProfunctorFirstAppliedBrand<Brand, A>(PhantomData<(Brand, A)>);
129
130/// An adapter that partially applies a `Profunctor` to its second argument, creating a `Contravariant` functor.
131///
132/// ### Examples
133///
134/// ```
135/// use fp_library::{
136/// brands::*,
137/// classes::contravariant::contramap,
138/// };
139///
140/// let f = |x: i32| x > 5;
141/// let is_long_int = contramap::<ProfunctorSecondAppliedBrand<RcFnBrand, bool>, _, _>(
142/// |s: String| s.len() as i32,
143/// std::rc::Rc::new(f) as std::rc::Rc<dyn Fn(i32) -> bool>,
144/// );
145/// assert_eq!(is_long_int("123456".to_string()), true);
146/// assert_eq!(is_long_int("123".to_string()), false);
147/// ```
148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
149pub struct ProfunctorSecondAppliedBrand<Brand, B>(PhantomData<(Brand, B)>);
150
151/// Brand for [`Rc`](`std::rc::Rc`) reference-counted pointer.
152#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
153pub struct RcBrand;
154
155/// Brand for [reference-counted][std::rc::Rc] [closures][Fn]
156/// (`Rc<dyn Fn(A) -> B>`).
157///
158/// This type alias provides a way to construct and type-check [`Rc`](`std::rc::Rc`)-wrapped
159/// closures in a generic context.
160pub type RcFnBrand = FnBrand<RcBrand>;
161
162/// Brand for [`Result`].
163#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
164pub struct ResultBrand;
165
166/// Brand for the partially-applied form of [`Result`] with the [`Err`] type applied.
167///
168/// This brand forms a [`crate::classes::Functor`] and [`crate::classes::Monad`] over the success ([`Ok`]) type.
169#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
170pub struct ResultErrAppliedBrand<E>(PhantomData<E>);
171
172/// Brand for the partially-applied form of [`Result`] with the [`Ok`] type applied.
173///
174/// This brand forms a [`crate::classes::Functor`] and [`crate::classes::Monad`] over the error ([`Err`]) type.
175#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
176pub struct ResultOkAppliedBrand<T>(PhantomData<T>);
177
178/// Brand for [`Step`](crate::types::Step).
179#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
180pub struct StepBrand;
181
182/// Brand for the partially-applied form of [`Step`](crate::types::Step) with the [`Done`](crate::types::Step::Done) type applied.
183#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
184pub struct StepDoneAppliedBrand<B>(PhantomData<B>);
185
186/// Brand for the partially-applied form of [`Step`](crate::types::Step) with the [`Loop`](crate::types::Step::Loop) type applied.
187#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
188pub struct StepLoopAppliedBrand<A>(PhantomData<A>);
189
190/// Brand for [`Thunk`](crate::types::Thunk).
191///
192/// Note: This is for `Thunk<'a, A>`, NOT for `Trampoline<A>`.
193/// `Trampoline` cannot implement HKT traits due to its `'static` requirement.
194#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
195pub struct ThunkBrand;
196
197/// Brand for [`TryLazy`](crate::types::TryLazy).
198#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
199pub struct TryLazyBrand<E, Config>(PhantomData<(E, Config)>);
200
201/// Brand for [`TryThunk`](crate::types::TryThunk) (Bifunctor).
202#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
203pub struct TryThunkBrand;
204
205/// Brand for [`TryThunk`](crate::types::TryThunk) with the error value applied (Functor over [`Ok`]).
206#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
207pub struct TryThunkErrAppliedBrand<E>(PhantomData<E>);
208
209/// Brand for [`TryThunk`](crate::types::TryThunk) with the success value applied (Functor over [`Err`]).
210#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
211pub struct TryThunkOkAppliedBrand<A>(PhantomData<A>);
212
213/// Brand for `(A,)`, with A not applied.
214#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
215pub struct Tuple1Brand;
216
217/// Brand for `(First, Second)`, with neither `First` nor `Second` applied.
218#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
219pub struct Tuple2Brand;
220
221/// Brand for `(First, Second)`, with `First` applied (Functor over `Second`).
222#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
223pub struct Tuple2FirstAppliedBrand<First>(PhantomData<First>);
224
225/// Brand for `(First, Second)`, with `Second` applied (Functor over `First`).
226#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
227pub struct Tuple2SecondAppliedBrand<Second>(PhantomData<Second>);
228
229/// Brand for [`Vec`].
230#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
231pub struct VecBrand;