use core::convert::identity;
pub trait Bifunctor<'a, A, B> {
type Target<T, U>;
fn bimap<C, D, L, R>(self, left: L, right: R) -> Self::Target<C, D>
where
L: Fn(A) -> C + 'a,
R: Fn(B) -> D + 'a;
fn lmap<C, L>(self, left: L) -> Self::Target<C, B>
where
Self: Sized,
B: 'a,
L: Fn(A) -> C + 'a,
{
self.bimap(left, identity)
}
fn rmap<D, R>(self, right: R) -> Self::Target<A, D>
where
Self: Sized,
A: 'a,
R: Fn(B) -> D + 'a,
{
self.bimap(identity, right)
}
}
impl<A, B> Bifunctor<'_, A, B> for Result<A, B> {
type Target<T, U> = Result<T, U>;
fn bimap<C, D, L, R>(self, left: L, right: R) -> Self::Target<C, D>
where
L: Fn(A) -> C,
R: Fn(B) -> D,
{
match self {
Ok(a) => Ok(left(a)),
Err(b) => Err(right(b)),
}
}
}
impl<A, B> Bifunctor<'_, A, B> for Vec<(A, B)> {
type Target<T, U> = Vec<(T, U)>;
fn bimap<C, D, L, R>(self, left: L, right: R) -> Self::Target<C, D>
where
L: Fn(A) -> C,
R: Fn(B) -> D,
{
self.into_iter().map(|(a, b)| (left(a), right(b))).collect()
}
}