#[fp_macros::document_module]
mod inner {
use {
crate::{
Apply,
brands::Tuple1Brand,
classes::{
Applicative,
ApplyFirst,
ApplySecond,
CloneableFn,
Foldable,
Functor,
Lift,
MonadRec,
Monoid,
Pointed,
Semiapplicative,
Semimonad,
Traversable,
},
impl_kind,
kinds::*,
},
core::ops::ControlFlow,
fp_macros::*,
};
impl_kind! {
for Tuple1Brand {
type Of<A> = (A,);
}
}
impl_kind! {
for Tuple1Brand {
type Of<'a, A: 'a>: 'a = (A,);
}
}
impl Functor for Tuple1Brand {
#[document_signature]
#[document_type_parameters(
"The lifetime of the value.",
"The type of the value inside the tuple.",
"The type of the result of applying the function."
)]
#[document_parameters("The function to apply.", "The tuple to map over.")]
#[document_returns("A new 1-tuple containing the result of applying the function.")]
#[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>) {
(func(fa.0),)
}
}
impl Lift for Tuple1Brand {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the first tuple's value.",
"The type of the second tuple's value.",
"The return type of the function."
)]
#[document_parameters(
"The binary function to apply.",
"The first tuple.",
"The second tuple."
)]
#[document_returns("A new 1-tuple containing the result of applying the function.")]
#[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: 'a,
B: 'a,
C: 'a, {
(func(fa.0, fb.0),)
}
}
impl Pointed for Tuple1Brand {
#[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 1-tuple containing the value.")]
#[document_examples]
fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
(a,)
}
}
impl ApplyFirst for Tuple1Brand {}
impl ApplySecond for Tuple1Brand {}
impl Semiapplicative for Tuple1Brand {
#[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 tuple containing the function.",
"The tuple containing the value."
)]
#[document_returns("A new 1-tuple containing the result of applying the function.")]
#[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>) {
(ff.0(fa.0),)
}
}
impl Semimonad for Tuple1Brand {
#[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 tuple.",
"The function to apply to the value inside the tuple."
)]
#[document_returns("The result of applying `f` to the value.")]
#[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>) {
func(ma.0)
}
}
impl Foldable for Tuple1Brand {
#[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 each element and the accumulator.",
"The initial value of the accumulator.",
"The tuple to fold."
)]
#[document_returns("The final accumulator value.")]
#[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 function to apply to the accumulator and each element.",
"The initial value of the accumulator.",
"The tuple to fold."
)]
#[document_returns("The final accumulator value.")]
#[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 thread-safe function to map each element to a monoid.",
"The tuple to fold."
)]
#[document_returns("The monoid value.")]
#[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)
}
}
impl Traversable for Tuple1Brand {
#[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 tuple to traverse."
)]
#[document_returns("The 1-tuple 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, {
F::map(|b| (b,), func(ta.0))
}
#[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 tuple containing the applicative value.")]
#[document_returns("The 1-tuple 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, {
F::map(|a| (a,), ta.0)
}
}
impl MonadRec for Tuple1Brand {
#[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 1-tuple containing the result of the computation.")]
#[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 current = initial;
loop {
match func(current).0 {
ControlFlow::Continue(next) => current = next,
ControlFlow::Break(b) => return (b,),
}
}
}
}
}
#[cfg(test)]
mod tests {
use {
crate::{
brands::{
OptionBrand,
RcFnBrand,
Tuple1Brand,
},
classes::{
CloneableFn,
functor::map,
pointed::pure,
semiapplicative::apply,
semimonad::bind,
},
functions::{
compose,
identity,
},
},
quickcheck_macros::quickcheck,
};
#[quickcheck]
fn functor_identity(x: i32) -> bool {
let x = (x,);
map::<Tuple1Brand, _, _>(identity, x) == x
}
#[quickcheck]
fn functor_composition(x: i32) -> bool {
let x = (x,);
let f = |x: i32| x.wrapping_add(1);
let g = |x: i32| x.wrapping_mul(2);
map::<Tuple1Brand, _, _>(compose(f, g), x)
== map::<Tuple1Brand, _, _>(f, map::<Tuple1Brand, _, _>(g, x))
}
#[quickcheck]
fn applicative_identity(v: i32) -> bool {
let v = (v,);
apply::<RcFnBrand, Tuple1Brand, _, _>(
pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(identity)),
v,
) == v
}
#[quickcheck]
fn applicative_homomorphism(x: i32) -> bool {
let f = |x: i32| x.wrapping_mul(2);
apply::<RcFnBrand, Tuple1Brand, _, _>(
pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(f)),
pure::<Tuple1Brand, _>(x),
) == pure::<Tuple1Brand, _>(f(x))
}
#[quickcheck]
fn applicative_composition(
w: i32,
u_val: i32,
v_val: i32,
) -> bool {
let w = (w,);
let v_fn = move |x: i32| x.wrapping_mul(v_val);
let u_fn = move |x: i32| x.wrapping_add(u_val);
let v = pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(v_fn));
let u = pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(u_fn));
let vw = apply::<RcFnBrand, Tuple1Brand, _, _>(v.clone(), w);
let rhs = apply::<RcFnBrand, Tuple1Brand, _, _>(u.clone(), vw);
let composed = move |x| u_fn(v_fn(x));
let uv = pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(composed));
let lhs = apply::<RcFnBrand, Tuple1Brand, _, _>(uv, w);
lhs == rhs
}
#[quickcheck]
fn applicative_interchange(y: i32) -> bool {
let f = |x: i32| x.wrapping_mul(2);
let u = pure::<Tuple1Brand, _>(<RcFnBrand as CloneableFn>::new(f));
let lhs = apply::<RcFnBrand, Tuple1Brand, _, _>(u.clone(), pure::<Tuple1Brand, _>(y));
let rhs_fn =
<RcFnBrand as CloneableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
let rhs = apply::<RcFnBrand, Tuple1Brand, _, _>(pure::<Tuple1Brand, _>(rhs_fn), u);
lhs == rhs
}
#[quickcheck]
fn monad_left_identity(a: i32) -> bool {
let f = |x: i32| (x.wrapping_mul(2),);
bind::<Tuple1Brand, _, _>(pure::<Tuple1Brand, _>(a), f) == f(a)
}
#[quickcheck]
fn monad_right_identity(m: i32) -> bool {
let m = (m,);
bind::<Tuple1Brand, _, _>(m, pure::<Tuple1Brand, _>) == m
}
#[quickcheck]
fn monad_associativity(m: i32) -> bool {
let m = (m,);
let f = |x: i32| (x.wrapping_mul(2),);
let g = |x: i32| (x.wrapping_add(1),);
bind::<Tuple1Brand, _, _>(bind::<Tuple1Brand, _, _>(m, f), g)
== bind::<Tuple1Brand, _, _>(m, |x| bind::<Tuple1Brand, _, _>(f(x), g))
}
#[test]
fn map_test() {
assert_eq!(map::<Tuple1Brand, _, _>(|x: i32| x + 1, (1,)), (2,));
}
#[test]
fn bind_test() {
assert_eq!(bind::<Tuple1Brand, _, _>((1,), |x| (x + 1,)), (2,));
}
#[test]
fn fold_right_test() {
assert_eq!(
crate::classes::foldable::fold_right::<RcFnBrand, Tuple1Brand, _, _>(
|x: i32, acc| x + acc,
0,
(1,)
),
1
);
}
#[test]
fn fold_left_test() {
assert_eq!(
crate::classes::foldable::fold_left::<RcFnBrand, Tuple1Brand, _, _>(
|acc, x: i32| acc + x,
0,
(1,)
),
1
);
}
#[test]
fn traverse_test() {
assert_eq!(
crate::classes::traversable::traverse::<Tuple1Brand, _, _, OptionBrand>(
|x: i32| Some(x + 1),
(1,)
),
Some((2,))
);
}
#[quickcheck]
fn monad_rec_identity(x: i32) -> bool {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
tail_rec_m::<Tuple1Brand, _, _>(|a| (ControlFlow::Break(a),), x) == (x,)
}
#[test]
fn monad_rec_sum_range() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let result = tail_rec_m::<Tuple1Brand, _, _>(
|(n, acc)| {
if n == 0 {
(ControlFlow::Break(acc),)
} else {
(ControlFlow::Continue((n - 1, acc + n)),)
}
},
(100i64, 0i64),
);
assert_eq!(result, (5050,));
}
#[test]
fn monad_rec_stack_safety() {
use {
crate::classes::monad_rec::tail_rec_m,
core::ops::ControlFlow,
};
let iterations: i64 = 200_000;
let result = tail_rec_m::<Tuple1Brand, _, _>(
|acc| {
if acc < iterations {
(ControlFlow::Continue(acc + 1),)
} else {
(ControlFlow::Break(acc),)
}
},
0i64,
);
assert_eq!(result, (iterations,));
}
}