#[fp_macros::document_module]
mod inner {
use {
crate::{
Apply,
brands::{
PairBrand,
PairFirstAppliedBrand,
PairSecondAppliedBrand,
},
classes::{
Applicative,
ApplyFirst,
ApplySecond,
Bifoldable,
Bifunctor,
Bitraversable,
CloneableFn,
Foldable,
Functor,
Lift,
MonadRec,
Monoid,
Pointed,
Semiapplicative,
Semigroup,
Semimonad,
Traversable,
},
impl_kind,
kinds::*,
},
core::ops::ControlFlow,
fp_macros::*,
};
#[document_type_parameters("The type of the first value.", "The type of the second value.")]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Pair<First, Second>(
pub First,
pub Second,
);
impl_kind! {
for PairBrand {
type Of<First,Second> = Pair<First, Second>;
}
}
impl_kind! {
for PairBrand {
type Of<'a, First: 'a, Second: 'a>: 'a = Pair<First, Second>;
}
}
#[document_type_parameters("The type of the first value.", "The type of the second value.")]
#[document_parameters("The pair instance.")]
impl<First, Second> Pair<First, Second> {
#[document_signature]
#[document_type_parameters(
"The type of the mapped first value.",
"The type of the mapped second value."
)]
#[document_parameters(
"The function to apply to the first value.",
"The function to apply to the second value."
)]
#[document_returns("A new pair containing the mapped values.")]
#[document_examples]
pub fn bimap<B, D>(
self,
f: impl FnOnce(First) -> B,
g: impl FnOnce(Second) -> D,
) -> Pair<B, D> {
Pair(f(self.0), g(self.1))
}
#[document_signature]
#[document_type_parameters("The type of the mapped first value.")]
#[document_parameters("The function to apply to the first value.")]
#[document_returns("A new pair with the transformed first value.")]
#[document_examples]
pub fn map_first<B>(
self,
f: impl FnOnce(First) -> B,
) -> Pair<B, Second> {
Pair(f(self.0), self.1)
}
#[document_signature]
#[document_type_parameters("The type of the mapped second value.")]
#[document_parameters("The function to apply to the second value.")]
#[document_returns("A new pair with the transformed second value.")]
#[document_examples]
pub fn map_second<D>(
self,
g: impl FnOnce(Second) -> D,
) -> Pair<First, D> {
Pair(self.0, g(self.1))
}
#[document_signature]
#[document_type_parameters("The result type.")]
#[document_parameters(
"The function to apply to the first value.",
"The function to apply to the second value.",
"The function to combine the results."
)]
#[document_returns("The combined result.")]
#[document_examples]
pub fn fold<C>(
self,
f: impl FnOnce(First) -> C,
g: impl FnOnce(Second) -> C,
combine: impl FnOnce(C, C) -> C,
) -> C {
combine(f(self.0), g(self.1))
}
#[document_signature]
#[document_type_parameters("The accumulator type.")]
#[document_parameters(
"The step function for the first value.",
"The step function for the second value.",
"The initial accumulator."
)]
#[document_returns("The result of folding: `f(first, g(second, z))`.")]
#[document_examples]
pub fn bi_fold_right<C>(
self,
f: impl FnOnce(First, C) -> C,
g: impl FnOnce(Second, C) -> C,
z: C,
) -> C {
f(self.0, g(self.1, z))
}
#[document_signature]
#[document_type_parameters("The accumulator type.")]
#[document_parameters(
"The step function for the first value.",
"The step function for the second value.",
"The initial accumulator."
)]
#[document_returns("The result of folding: `g(f(z, first), second)`.")]
#[document_examples]
pub fn bi_fold_left<C>(
self,
f: impl FnOnce(C, First) -> C,
g: impl FnOnce(C, Second) -> C,
z: C,
) -> C {
g(f(z, self.0), self.1)
}
#[document_signature]
#[document_type_parameters("The monoid type.")]
#[document_parameters(
"The function mapping the first value to the monoid.",
"The function mapping the second value to the monoid."
)]
#[document_returns("The combined monoid value.")]
#[document_examples]
pub fn bi_fold_map<M: Semigroup>(
self,
f: impl FnOnce(First) -> M,
g: impl FnOnce(Second) -> M,
) -> M {
Semigroup::append(f(self.0), g(self.1))
}
}
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first value.",
"The type of the second value."
)]
#[document_parameters("The pair instance.")]
impl<'a, First: 'a, Second: 'a> Pair<First, Second> {
#[document_signature]
#[document_type_parameters(
"The output type for the first value.",
"The output type for the second value.",
"The applicative context."
)]
#[document_parameters(
"The function for the first value.",
"The function for the second value."
)]
#[document_returns("A pair of the transformed values wrapped in the applicative context.")]
#[document_examples]
pub fn bi_traverse<C: 'a + Clone, D: 'a + Clone, F: Applicative>(
self,
f: impl Fn(First) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
g: impl Fn(Second) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, D>) + 'a,
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Pair<C, D>>)
where
Pair<C, D>: Clone, {
F::lift2(|c, d| Pair(c, d), f(self.0), g(self.1))
}
}
#[document_type_parameters("The type of the first value.", "The type of the second value.")]
#[document_parameters("The pair instance.")]
impl<First: Semigroup, Second> Pair<First, Second> {
#[document_signature]
#[document_type_parameters("The type of the new second value.")]
#[document_parameters("The function to apply to the second value.")]
#[document_returns(
"A new pair where the first values are combined and the second value is transformed."
)]
#[document_examples]
pub fn bind<C>(
self,
f: impl FnOnce(Second) -> Pair<First, C>,
) -> Pair<First, C> {
let Pair(first, second) = self;
let Pair(next_first, next_second) = f(second);
Pair(Semigroup::append(first, next_first), next_second)
}
}
#[document_type_parameters("The type of the first value.", "The type of the second value.")]
#[document_parameters("The pair instance.")]
impl<First, Second: Semigroup> Pair<First, Second> {
#[document_signature]
#[document_type_parameters("The type of the new first value.")]
#[document_parameters("The function to apply to the first value.")]
#[document_returns(
"A new pair where the first value is transformed and the second values are combined."
)]
#[document_examples]
pub fn bind_first<C>(
self,
f: impl FnOnce(First) -> Pair<C, Second>,
) -> Pair<C, Second> {
let Pair(first, second) = self;
let Pair(next_first, next_second) = f(first);
Pair(next_first, Semigroup::append(second, next_second))
}
}
impl Bifunctor for PairBrand {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first value.",
"The type of the mapped first value.",
"The type of the second value.",
"The type of the mapped second value."
)]
#[document_parameters(
"The function to apply to the first value.",
"The function to apply to the second value.",
"The pair to map over."
)]
#[document_returns("A new pair containing the mapped values.")]
#[document_examples]
fn bimap<'a, A: 'a, B: 'a, C: 'a, D: 'a>(
f: impl Fn(A) -> B + 'a,
g: impl Fn(C) -> D + 'a,
p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
) -> Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, D>) {
p.bimap(f, g)
}
}
impl Bifoldable for PairBrand {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the first value.",
"The type of the second value.",
"The accumulator type."
)]
#[document_parameters(
"The step function for the first value.",
"The step function for the second value.",
"The initial accumulator.",
"The pair to fold."
)]
#[document_returns("`f(a, g(b, z))`.")]
#[document_examples]
fn bi_fold_right<'a, FnBrand: CloneableFn + 'a, A: 'a + Clone, B: 'a + Clone, C: 'a>(
f: impl Fn(A, C) -> C + 'a,
g: impl Fn(B, C) -> C + 'a,
z: C,
p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
) -> C {
p.bi_fold_right(f, g, z)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the first value.",
"The type of the second value.",
"The accumulator type."
)]
#[document_parameters(
"The step function for the first value.",
"The step function for the second value.",
"The initial accumulator.",
"The pair to fold."
)]
#[document_returns("`g(f(z, a), b)`.")]
#[document_examples]
fn bi_fold_left<'a, FnBrand: CloneableFn + 'a, A: 'a + Clone, B: 'a + Clone, C: 'a>(
f: impl Fn(C, A) -> C + 'a,
g: impl Fn(C, B) -> C + 'a,
z: C,
p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
) -> C {
p.bi_fold_left(f, g, z)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the first value.",
"The type of the second value.",
"The monoid type."
)]
#[document_parameters(
"The function mapping the first value to the monoid.",
"The function mapping the second value to the monoid.",
"The pair to fold."
)]
#[document_returns("`Semigroup::append(f(a), g(b))`.")]
#[document_examples]
fn bi_fold_map<'a, FnBrand: CloneableFn + 'a, A: 'a + Clone, B: 'a + Clone, M>(
f: impl Fn(A) -> M + 'a,
g: impl Fn(B) -> M + 'a,
p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
) -> M
where
M: Monoid + 'a, {
p.bi_fold_map(f, g)
}
}
impl Bitraversable for PairBrand {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first value.",
"The type of the second value.",
"The output type for the first value.",
"The output type for the second value.",
"The applicative context."
)]
#[document_parameters(
"The function applied to the first value.",
"The function applied to the second value.",
"The pair to traverse."
)]
#[document_returns("`lift2(Pair, f(a), g(b))`.")]
#[document_examples]
fn bi_traverse<
'a,
A: 'a + Clone,
B: 'a + Clone,
C: 'a + Clone,
D: 'a + Clone,
F: Applicative,
>(
f: impl Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
g: impl Fn(B) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, D>) + 'a,
p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, C, D>)>)
{
p.bi_traverse::<C, D, F>(f, g)
}
}
impl_kind! {
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: 'static> for PairFirstAppliedBrand<First> {
type Of<'a, A: 'a>: 'a = Pair<First, A>;
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: 'static> Functor for PairFirstAppliedBrand<First> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the second value.",
"The type of the result of applying the function."
)]
#[document_parameters(
"The function to apply to the second value.",
"The pair to map over."
)]
#[document_returns(
"A new pair containing the result of applying the function to the second value."
)]
#[document_examples]
fn map<'a, A: 'a, B: 'a>(
func: impl Fn(A) -> B + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
fa.map_second(func)
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> Lift for PairFirstAppliedBrand<First>
where
First: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first second value.",
"The type of the second second value.",
"The type of the result second value."
)]
#[document_parameters(
"The binary function to apply to the second values.",
"The first pair.",
"The second pair."
)]
#[document_returns(
"A new pair where the first values are combined using `Semigroup::append` and the second values are combined using `f`."
)]
#[document_examples]
fn lift2<'a, A, B, C>(
func: impl Fn(A, B) -> C + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
where
A: Clone + 'a,
B: Clone + 'a,
C: 'a, {
let Pair(fa_first, fa_second) = fa;
let Pair(fb_first, fb_second) = fb;
Pair(Semigroup::append(fa_first, fb_first), func(fa_second, fb_second))
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> Pointed for PairFirstAppliedBrand<First>
where
First: Monoid,
{
#[document_signature]
#[document_type_parameters("The lifetime of the value.", "The type of the value to wrap.")]
#[document_parameters("The value to wrap.")]
#[document_returns("A pair containing the empty value of the first type and `a`.")]
#[document_examples]
fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
Pair(Monoid::empty(), a)
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + Semigroup + 'static> ApplyFirst for PairFirstAppliedBrand<First> {}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + Semigroup + 'static> ApplySecond for PairFirstAppliedBrand<First> {}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> Semiapplicative for PairFirstAppliedBrand<First>
where
First: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function wrapper.",
"The type of the input value.",
"The type of the output value."
)]
#[document_parameters(
"The pair containing the function.",
"The pair containing the value."
)]
#[document_returns(
"A new pair where the first values are combined and the function is applied to the second value."
)]
#[document_examples]
fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
Pair(Semigroup::append(ff.0, fa.0), ff.1(fa.1))
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> Semimonad for PairFirstAppliedBrand<First>
where
First: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the result of the first computation.",
"The type of the result of the second computation."
)]
#[document_parameters("The first pair.", "The function to apply to the second value.")]
#[document_returns("A new pair where the first values are combined.")]
#[document_examples]
fn bind<'a, A: 'a, B: 'a>(
ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
ma.bind(func)
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> MonadRec for PairFirstAppliedBrand<First>
where
First: Monoid,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the initial value and loop state.",
"The type of the result."
)]
#[document_parameters("The step function.", "The initial value.")]
#[document_returns("A pair with the accumulated first value and the final result.")]
#[document_examples]
fn tail_rec_m<'a, A: 'a, B: 'a>(
func: impl Fn(
A,
)
-> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, ControlFlow<B, A>>)
+ 'a,
initial: A,
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
let mut acc: First = Monoid::empty();
let mut current = initial;
loop {
let Pair(first, step) = func(current);
acc = Semigroup::append(acc, first);
match step {
ControlFlow::Continue(next) => current = next,
ControlFlow::Break(b) => return Pair(acc, b),
}
}
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: 'static> Foldable for PairFirstAppliedBrand<First> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the accumulator."
)]
#[document_parameters("The folding function.", "The initial value.", "The pair to fold.")]
#[document_returns("`func(a, initial)`.")]
#[document_examples]
fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(A, B) -> B + 'a,
initial: B,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: CloneableFn + 'a, {
func(fa.1, initial)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the accumulator."
)]
#[document_parameters(
"The function to apply to the accumulator and each element.",
"The initial value of the accumulator.",
"The identity to fold."
)]
#[document_returns("`func(initial, a)`.")]
#[document_examples]
fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(B, A) -> B + 'a,
initial: B,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: CloneableFn + 'a, {
func(initial, fa.1)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the monoid."
)]
#[document_parameters("The mapping function.", "The pair to fold.")]
#[document_returns("`func(a)`.")]
#[document_examples]
fn fold_map<'a, FnBrand, A: 'a + Clone, M>(
func: impl Fn(A) -> M + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> M
where
M: Monoid + 'a,
FnBrand: CloneableFn + 'a, {
func(fa.1)
}
}
#[document_type_parameters("The type of the first value in the pair.")]
impl<First: Clone + 'static> Traversable for PairFirstAppliedBrand<First> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the elements in the traversable structure.",
"The type of the elements in the resulting traversable structure.",
"The applicative context."
)]
#[document_parameters(
"The function to apply to each element, returning a value in an applicative context.",
"The pair to traverse."
)]
#[document_returns("The pair wrapped in the applicative context.")]
#[document_examples]
fn traverse<'a, A: 'a + Clone, B: 'a + Clone, F: Applicative>(
func: impl Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
where
Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone, {
let Pair(first, second) = ta;
F::map(move |b| Pair(first.clone(), b), func(second))
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the elements in the traversable structure.",
"The applicative context."
)]
#[document_parameters("The pair containing the applicative value.")]
#[document_returns("The pair wrapped in the applicative context.")]
#[document_examples]
fn sequence<'a, A: 'a + Clone, F: Applicative>(
ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
where
Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone, {
let Pair(first, second) = ta;
F::map(move |a| Pair(first.clone(), a), second)
}
}
impl_kind! {
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: 'static> for PairSecondAppliedBrand<Second> {
type Of<'a, A: 'a>: 'a = Pair<A, Second>;
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: 'static> Functor for PairSecondAppliedBrand<Second> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first value.",
"The type of the result of applying the function."
)]
#[document_parameters("The function to apply to the first value.", "The pair to map over.")]
#[document_returns(
"A new pair containing the result of applying the function to the first value."
)]
#[document_examples]
fn map<'a, A: 'a, B: 'a>(
func: impl Fn(A) -> B + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
fa.map_first(func)
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> Lift for PairSecondAppliedBrand<Second>
where
Second: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first first value.",
"The type of the second first value.",
"The type of the result first value."
)]
#[document_parameters(
"The binary function to apply to the first values.",
"The first pair.",
"The second pair."
)]
#[document_returns(
"A new pair where the first values are combined using `f` and the second values are combined using `Semigroup::append`."
)]
#[document_examples]
fn lift2<'a, A, B, C>(
func: impl Fn(A, B) -> C + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
where
A: Clone + 'a,
B: Clone + 'a,
C: 'a, {
Pair(func(fa.0, fb.0), Semigroup::append(fa.1, fb.1))
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> Pointed for PairSecondAppliedBrand<Second>
where
Second: Monoid,
{
#[document_signature]
#[document_type_parameters("The lifetime of the value.", "The type of the value to wrap.")]
#[document_parameters("The value to wrap.")]
#[document_returns("A pair containing `a` and the empty value of the second type.")]
#[document_examples]
fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
Pair(a, Monoid::empty())
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + Semigroup + 'static> ApplyFirst for PairSecondAppliedBrand<Second> {}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + Semigroup + 'static> ApplySecond for PairSecondAppliedBrand<Second> {}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> Semiapplicative for PairSecondAppliedBrand<Second>
where
Second: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function wrapper.",
"The type of the input value.",
"The type of the output value."
)]
#[document_parameters(
"The pair containing the function (in Err).",
"The pair containing the value (in Err)."
)]
#[document_returns(
"`Err(f(a))` if both are `Err`, otherwise the first success encountered."
)]
#[document_examples]
fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
Pair(ff.0(fa.0), Semigroup::append(ff.1, fa.1))
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> Semimonad for PairSecondAppliedBrand<Second>
where
Second: Semigroup,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the result of the first computation.",
"The type of the result of the second computation."
)]
#[document_parameters("The first result.", "The function to apply to the error value.")]
#[document_returns(
"The result of applying `f` to the error if `ma` is `Err`, otherwise the original success."
)]
#[document_examples]
fn bind<'a, A: 'a, B: 'a>(
ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
ma.bind_first(func)
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> MonadRec for PairSecondAppliedBrand<Second>
where
Second: Monoid,
{
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the initial value and loop state.",
"The type of the result."
)]
#[document_parameters("The step function.", "The initial value.")]
#[document_returns("A pair with the final result and the accumulated second value.")]
#[document_examples]
fn tail_rec_m<'a, A: 'a, B: 'a>(
func: impl Fn(
A,
)
-> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, ControlFlow<B, A>>)
+ 'a,
initial: A,
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
let mut acc: Second = Monoid::empty();
let mut current = initial;
loop {
let Pair(step, second) = func(current);
acc = Semigroup::append(acc, second);
match step {
ControlFlow::Continue(next) => current = next,
ControlFlow::Break(b) => return Pair(b, acc),
}
}
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: 'static> Foldable for PairSecondAppliedBrand<Second> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the accumulator."
)]
#[document_parameters("The folding function.", "The initial value.", "The result to fold.")]
#[document_returns("`func(a, initial)` if `fa` is `Err(a)`, otherwise `initial`.")]
#[document_examples]
fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(A, B) -> B + 'a,
initial: B,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: CloneableFn + 'a, {
func(fa.0, initial)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the accumulator."
)]
#[document_parameters("The folding function.", "The initial value.", "The result to fold.")]
#[document_returns("`func(initial, a)` if `fa` is `Err(a)`, otherwise `initial`.")]
#[document_examples]
fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(B, A) -> B + 'a,
initial: B,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: CloneableFn + 'a, {
func(initial, fa.0)
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the cloneable function to use.",
"The type of the elements in the structure.",
"The type of the monoid."
)]
#[document_parameters("The mapping function.", "The result to fold.")]
#[document_returns("`func(a)` if `fa` is `Err(a)`, otherwise `M::empty()`.")]
#[document_examples]
fn fold_map<'a, FnBrand, A: 'a + Clone, M>(
func: impl Fn(A) -> M + 'a,
fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> M
where
M: Monoid + 'a,
FnBrand: CloneableFn + 'a, {
func(fa.0)
}
}
#[document_type_parameters("The type of the second value in the pair.")]
impl<Second: Clone + 'static> Traversable for PairSecondAppliedBrand<Second> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the elements in the traversable structure.",
"The type of the elements in the resulting traversable structure.",
"The applicative context."
)]
#[document_parameters("The function to apply.", "The result to traverse.")]
#[document_returns("The result wrapped in the applicative context.")]
#[document_examples]
fn traverse<'a, A: 'a + Clone, B: 'a + Clone, F: Applicative>(
func: impl Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
where
Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone, {
let Pair(first, second) = ta;
F::map(move |b| Pair(b, second.clone()), func(first))
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the elements in the traversable structure.",
"The applicative context."
)]
#[document_parameters("The result containing the applicative value.")]
#[document_returns("The result wrapped in the applicative context.")]
#[document_examples]
fn sequence<'a, A: 'a + Clone, F: Applicative>(
ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
where
Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone, {
let Pair(first, second) = ta;
F::map(move |a| Pair(a, second.clone()), first)
}
}
}
pub use inner::*;
#[cfg(test)]
mod tests {
use {
super::inner::*,
crate::{
brands::*,
classes::{
CloneableFn,
bifunctor::*,
},
functions::*,
},
quickcheck_macros::quickcheck,
};
#[test]
fn test_bimap() {
let x = Pair(1, 5);
assert_eq!(bimap::<PairBrand, _, _, _, _>(|a| a + 1, |b| b * 2, x), Pair(2, 10));
}
#[quickcheck]
fn bifunctor_identity(
first: String,
second: i32,
) -> bool {
let x = Pair(first, second);
bimap::<PairBrand, _, _, _, _>(identity, identity, x.clone()) == x
}
#[quickcheck]
fn bifunctor_composition(
first: i32,
second: i32,
) -> bool {
let x = Pair(first, second);
let f = |x: i32| x.wrapping_add(1);
let g = |x: i32| x.wrapping_mul(2);
let h = |x: i32| x.wrapping_sub(1);
let i = |x: i32| if x == 0 { 0 } else { x.wrapping_div(2) };
bimap::<PairBrand, _, _, _, _>(compose(f, g), compose(h, i), x)
== bimap::<PairBrand, _, _, _, _>(f, h, bimap::<PairBrand, _, _, _, _>(g, i, x))
}
#[quickcheck]
fn functor_identity(
first: String,
second: i32,
) -> bool {
let x = Pair(first, second);
map::<PairFirstAppliedBrand<String>, _, _>(identity, x.clone()) == x
}
#[quickcheck]
fn functor_composition(
first: String,
second: i32,
) -> bool {
let x = Pair(first, second);
let f = |x: i32| x.wrapping_add(1);
let g = |x: i32| x.wrapping_mul(2);
map::<PairFirstAppliedBrand<String>, _, _>(compose(f, g), x.clone())
== map::<PairFirstAppliedBrand<String>, _, _>(
f,
map::<PairFirstAppliedBrand<String>, _, _>(g, x),
)
}
#[quickcheck]
fn applicative_identity(
first: String,
second: i32,
) -> bool {
let v = Pair(first, second);
apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(
pure::<PairFirstAppliedBrand<String>, _>(<RcFnBrand as CloneableFn>::new(identity)),
v.clone(),
) == v
}
#[quickcheck]
fn applicative_homomorphism(x: i32) -> bool {
let f = |x: i32| x.wrapping_mul(2);
apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(
pure::<PairFirstAppliedBrand<String>, _>(<RcFnBrand as CloneableFn>::new(f)),
pure::<PairFirstAppliedBrand<String>, _>(x),
) == pure::<PairFirstAppliedBrand<String>, _>(f(x))
}
#[quickcheck]
fn applicative_composition(
w_first: String,
w_second: i32,
u_seed: i32,
v_seed: i32,
) -> bool {
let w = Pair(w_first, w_second);
let u_fn = <RcFnBrand as CloneableFn>::new(move |x: i32| x.wrapping_add(u_seed));
let u = pure::<PairFirstAppliedBrand<String>, _>(u_fn);
let v_fn = <RcFnBrand as CloneableFn>::new(move |x: i32| x.wrapping_mul(v_seed));
let v = pure::<PairFirstAppliedBrand<String>, _>(v_fn);
let vw = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(v.clone(), w.clone());
let rhs = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(u.clone(), vw);
let compose_fn = <RcFnBrand as CloneableFn>::new(|f: std::rc::Rc<dyn Fn(i32) -> i32>| {
let f = f.clone();
<RcFnBrand as CloneableFn>::new(move |g: std::rc::Rc<dyn Fn(i32) -> i32>| {
let f = f.clone();
let g = g.clone();
<RcFnBrand as CloneableFn>::new(move |x| f(g(x)))
})
});
let pure_compose = pure::<PairFirstAppliedBrand<String>, _>(compose_fn);
let u_applied = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(pure_compose, u);
let uv = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(u_applied, v);
let lhs = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(uv, w);
lhs == rhs
}
#[quickcheck]
fn applicative_interchange(
y: i32,
u_seed: i32,
) -> bool {
let f = move |x: i32| x.wrapping_mul(u_seed);
let u = pure::<PairFirstAppliedBrand<String>, _>(<RcFnBrand as CloneableFn>::new(f));
let lhs = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(
u.clone(),
pure::<PairFirstAppliedBrand<String>, _>(y),
);
let rhs_fn =
<RcFnBrand as CloneableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
let rhs = apply::<RcFnBrand, PairFirstAppliedBrand<String>, _, _>(
pure::<PairFirstAppliedBrand<String>, _>(rhs_fn),
u,
);
lhs == rhs
}
#[quickcheck]
fn monad_left_identity(a: i32) -> bool {
let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
bind::<PairFirstAppliedBrand<String>, _, _>(pure::<PairFirstAppliedBrand<String>, _>(a), f)
== f(a)
}
#[quickcheck]
fn monad_right_identity(
first: String,
second: i32,
) -> bool {
let m = Pair(first, second);
bind::<PairFirstAppliedBrand<String>, _, _>(
m.clone(),
pure::<PairFirstAppliedBrand<String>, _>,
) == m
}
#[quickcheck]
fn monad_associativity(
first: String,
second: i32,
) -> bool {
let m = Pair(first, second);
let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
let g = |x: i32| Pair("g".to_string(), x.wrapping_add(1));
bind::<PairFirstAppliedBrand<String>, _, _>(
bind::<PairFirstAppliedBrand<String>, _, _>(m.clone(), f),
g,
) == bind::<PairFirstAppliedBrand<String>, _, _>(m, |x| {
bind::<PairFirstAppliedBrand<String>, _, _>(f(x), g)
})
}
#[quickcheck]
fn monad_rec_first_applied_identity(x: i32) -> bool {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
tail_rec_m::<PairFirstAppliedBrand<String>, _, _>(
|a| Pair(String::new(), ControlFlow::Break(a)),
x,
) == Pair(String::new(), x)
}
#[test]
fn monad_rec_first_applied_accumulation() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let result = tail_rec_m::<PairFirstAppliedBrand<String>, _, _>(
|n: i32| {
if n < 3 {
Pair(format!("{n},"), ControlFlow::Continue(n + 1))
} else {
Pair(format!("{n}"), ControlFlow::Break(n))
}
},
0,
);
assert_eq!(result, Pair("0,1,2,3".to_string(), 3));
}
#[test]
fn monad_rec_first_applied_stack_safety() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let iterations: i64 = 200_000;
let result = tail_rec_m::<PairFirstAppliedBrand<Vec<()>>, _, _>(
|acc| {
if acc < iterations {
Pair(vec![], ControlFlow::Continue(acc + 1))
} else {
Pair(vec![], ControlFlow::Break(acc))
}
},
0i64,
);
assert_eq!(result, Pair(vec![], iterations));
}
#[quickcheck]
fn monad_rec_second_applied_identity(x: i32) -> bool {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
tail_rec_m::<PairSecondAppliedBrand<String>, _, _>(
|a| Pair(ControlFlow::Break(a), String::new()),
x,
) == Pair(x, String::new())
}
#[test]
fn monad_rec_second_applied_accumulation() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let result = tail_rec_m::<PairSecondAppliedBrand<String>, _, _>(
|n: i32| {
if n < 3 {
Pair(ControlFlow::Continue(n + 1), format!("{n},"))
} else {
Pair(ControlFlow::Break(n), format!("{n}"))
}
},
0,
);
assert_eq!(result, Pair(3, "0,1,2,3".to_string()));
}
#[test]
fn monad_rec_second_applied_stack_safety() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let iterations: i64 = 200_000;
let result = tail_rec_m::<PairSecondAppliedBrand<Vec<()>>, _, _>(
|acc| {
if acc < iterations {
Pair(ControlFlow::Continue(acc + 1), vec![])
} else {
Pair(ControlFlow::Break(acc), vec![])
}
},
0i64,
);
assert_eq!(result, Pair(iterations, vec![]));
}
}