//! Bifunctor is a type constructor that takes two type arguments and is a functor in both //! arguments. use crate::higher::Higher2; /// Bifunctor takes two type parameters instead of one, and is a functor in both of these /// parameters. It defines a function bimap, which allows for mapping over both arguments at the /// same time pub trait Bifunctor: Higher2 { /// Transform a `Self` into a `Self` by providing a transformation from `A` to `C` /// and from 'B' to 'D' fn bimap( self, f: impl FnMut(Self::Param1) -> C, g: impl FnMut(Self::Param2) -> D, ) -> Self::Target; } impl Bifunctor for Result { fn bimap(self, mut f: impl FnMut(A) -> C, mut g: impl FnMut(B) -> D) -> Result { match self { Ok(x) => Ok(f(x)), Err(e) => Err(g(e)), } } } impl Bifunctor for (A, B) { fn bimap(self, mut f: impl FnMut(A) -> C, mut g: impl FnMut(B) -> D) -> (C, D) { (f(self.0), g(self.1)) } } if_std! { use std::collections::HashMap; use std::hash::Hash; impl Bifunctor for HashMap { fn bimap( self, mut f: impl FnMut(A) -> C, mut g: impl FnMut(B) -> D, ) -> HashMap { self.into_iter().map(|(k, v)| (f(k), g(v))).collect() } } }