radn-rs/src/func/instances/composition.rs

166 lines
5.0 KiB
Rust

//! [Functor]s derived on compositions of other [Functor]s.
//!
//! For changing behaviour of existing [instances], see [`overload`].
//!
//! For [`future`]-[`result`] composition, see [`tryfuture`].
//!
//! [`overload`]: super::overload
//! [`future`]: super::future
//! [`result`]: super::result
//! [`tryfuture`]: super::tryfuture
use crate::func::class_prelude::*;
pub struct CompositionInstance<U, V>(U, V);
impl<'a, U: WeakFunctor<'a>, V: WeakFunctor<'a>> WeakFunctor<'a> for CompositionInstance<U, V> {
type F<A: 'a> = U::F<V::F<A>>;
}
impl<'a, U: Functor<'a>, V: Functor<'a>> Functor<'a> for CompositionInstance<U, V> {
fn fmap<A: 'a, B: 'a>(fa: Self::F<A>, f: impl 'a + FnOnce(A) -> B) -> Self::F<B> {
U::fmap(fa, |ua| V::fmap(ua, f))
}
fn replace<A: 'a, B: 'a>(fa: Self::F<A>, b: B) -> Self::F<B> {
U::fmap(fa, |ua| V::replace(ua, b))
}
fn void<A: 'a>(fa: Self::F<A>) -> Self::F<()> {
U::fmap(fa, |ua| V::void(ua))
}
}
impl<'a, U: Pure<'a>, V: Pure<'a>> Pure<'a> for CompositionInstance<U, V> {
fn pure<A: 'a>(a: A) -> Self::F<A> {
U::pure(V::pure(a))
}
}
/// Note: depends on the outer instance being [`ApplicativeLA2`] not [`ApplicativeSeq`].
impl<'a, U: ApplicativeLA2<'a>, V: ApplicativeSeq<'a>> ApplicativeSeq<'a>
for CompositionInstance<U, V>
{
fn seq<A: 'a, B: 'a>(ff: Self::F<impl 'a + FnOnce(A) -> B>, fa: Self::F<A>) -> Self::F<B> {
U::la2(ff, fa, V::seq)
}
}
impl<'a, U: ApplicativeLA2<'a>, V: ApplicativeLA2<'a>> ApplicativeLA2<'a>
for CompositionInstance<U, V>
{
fn la2<A: 'a, B: 'a, C: 'a>(
fa: Self::F<A>,
fb: Self::F<B>,
f: impl 'a + FnOnce(A, B) -> C,
) -> Self::F<C> {
U::la2(fa, fb, |ua, ub| V::la2(ua, ub, f))
}
}
impl<'a, U: ApplicativeTuple<'a>, V: ApplicativeTuple<'a>> ApplicativeTuple<'a>
for CompositionInstance<U, V>
{
fn tuple<A: 'a, B: 'a>(fab: (Self::F<A>, Self::F<B>)) -> Self::F<(A, B)> {
U::fmap(U::tuple(fab), V::tuple)
}
}
/// Note: depends on the inner instance being [`Functor`] not [`ApplicativeSelect`].
impl<'a, U: ApplicativeSelect<'a>, V: Functor<'a>> ApplicativeSelect<'a>
for CompositionInstance<U, V>
{
fn select<A: 'a, B: 'a>(fa: Self::F<A>, fb: Self::F<B>) -> SelectedWrapped<'a, A, B, Self> {
U::fmap(U::select(fa, fb), |selected| match selected {
Selected::A(ua, fb) => V::fmap(ua, |a| Selected::A(a, fb)),
Selected::B(fa, ub) => V::fmap(ub, |b| Selected::B(fa, b)),
})
}
}
impl<'a, U: Applicative<'a>, V: Applicative<'a>> Applicative<'a> for CompositionInstance<U, V> {
fn discard_first<A: 'a, B: 'a>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<B> {
U::la2(fa, fb, V::discard_first)
}
fn discard_second<A: 'a, B: 'a>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<A> {
U::la2(fa, fb, V::discard_second)
}
}
impl<'a, U: Monad<'a>, V: Monad<'a> + LocalFunctor<'a>> Monad<'a> for CompositionInstance<U, V> {
fn bind<A: 'a, B: 'a>(fa: Self::F<A>, f: impl 'a + FnOnce(A) -> Self::F<B>) -> Self::F<B> {
U::bind(fa, |ua| U::fmap(V::stuff::<_, U>(V::fmap(ua, f)), V::join))
}
fn iterate<B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<B> {
U::iterate(ComposedIterative(f))
}
/// Basis for how composition can be a [Monad].
///
/// ```text
/// U V U V A
/// U U V V A
/// U V A
/// ```
fn join<A: 'a>(ffa: Self::F<Self::F<A>>) -> Self::F<A> {
U::join(U::fmap(ffa, |ufa| U::fmap(V::stuff::<_, U>(ufa), V::join)))
}
}
struct ComposedIterative<F>(F);
impl<
'a,
U: Monad<'a>,
V: Monad<'a> + LocalFunctor<'a>,
F: Iterative<'a, T = CompositionInstance<U, V>>,
> Iterative<'a> for ComposedIterative<F>
{
type B = Wrap<'a, F::B, V>;
type T = U;
fn next(self) -> IterativeWrapped<'a, Self> {
let fstate = self.0.next();
U::fmap(fstate, |ustate| {
ControlFlow::Continue(Self(V::unstuff(ustate)?))
})
}
}
/// Note: fails in the inner instance not outer.
impl<'a, E: 'a, U: Monad<'a>, V: Fail<'a, E> + LocalFunctor<'a>> Fail<'a, E>
for CompositionInstance<U, V>
{
fn fail<A: 'a>(e: E) -> Self::F<A> {
U::pure(V::fail(e))
}
}
impl<'a, U: LocalFunctor<'a> + Functor<'a>, V: LocalFunctor<'a>> LocalFunctor<'a>
for CompositionInstance<U, V>
{
fn unstuff<A: 'a, B: 'a>(state: Self::F<ControlFlow<B, A>>) -> ControlFlow<Self::F<B>, A> {
U::unstuff(U::fmap(state, V::unstuff))
}
fn stuff<A: 'a, T: Pure<'a>>(fa: Self::F<T::F<A>>) -> T::F<Self::F<A>> {
U::stuff::<_, T>(U::fmap(fa, V::stuff::<_, T>))
}
}
impl<'a, U: SharedFunctor<'a> + Functor<'a>, V: SharedFunctor<'a>> SharedFunctor<'a>
for CompositionInstance<U, V>
{
type Shared<A: 'a + Clone> = U::Shared<V::Shared<A>>;
fn share<A: 'a + Clone>(fa: Self::F<A>) -> Self::Shared<A> {
U::share(U::fmap(fa, V::share))
}
fn unshare<A: 'a + Clone>(sa: Self::Shared<A>) -> Self::F<A> {
U::fmap(U::unshare(sa), V::unshare)
}
}