pub trait Bifoldable {
type Left;
type Right;
fn bifold<B>(
self,
on_left: impl FnOnce(Self::Left) -> B,
on_right: impl FnOnce(Self::Right) -> B,
) -> B;
}
pub mod either {
use crate::foundation::either::Either;
pub fn bifold<L, R, B>(
e: Either<R, L>,
on_left: impl FnOnce(L) -> B,
on_right: impl FnOnce(R) -> B,
) -> B {
match e {
Err(l) => on_left(l),
Ok(r) => on_right(r),
}
}
}
pub mod bitraverse {
use crate::foundation::either::Either;
use crate::kernel::Effect;
pub fn bitraverse<L, R, L2, R2, E, Rq, FL, FR>(
e: Either<R, L>,
fl: FL,
fr: FR,
) -> Effect<Either<R2, L2>, E, Rq>
where
FL: FnOnce(L) -> Effect<L2, E, Rq>,
FR: FnOnce(R) -> Effect<R2, E, Rq>,
{
match e {
Err(l) => fl(l).map(Err),
Ok(r) => fr(r).map(Ok),
}
}
}
#[cfg(test)]
mod tests {
use super::either::bifold;
#[test]
fn bifold_left() {
assert_eq!(
bifold::<i32, i32, i32>(Err(1i32), |l: i32| l + 1, |_r: i32| 0),
2
);
}
#[test]
fn bifold_right() {
assert_eq!(
bifold::<i32, i32, i32>(Ok(1i32), |_l: i32| 0, |r: i32| r + 10),
11
);
}
mod bitraverse_tests {
use crate::algebra::bifoldable::bitraverse::bitraverse;
use crate::foundation::either::Either;
use crate::{Exit, pure, run_test};
#[test]
fn traverses_left_branch() {
let e: Either<(), i32> = Err(5);
let exit: Exit<Either<(), String>, ()> = run_test(
bitraverse(e, |l| pure(l.to_string()), |_r: ()| pure(())),
(),
);
assert_eq!(exit, Exit::succeed(Err("5".into())));
}
#[test]
fn traverses_right_branch() {
let e: Either<i32, ()> = Ok(7);
let exit: Exit<Either<String, ()>, ()> = run_test(
bitraverse(e, |_l: ()| pure(()), |r| pure(r.to_string())),
(),
);
assert_eq!(exit, Exit::succeed(Ok("7".into())));
}
}
}