book-monads/src/ch04/s01-alternatives.md
2023-05-03 12:05:38 +00:00

2.4 KiB

Atlernatives to Functor trait

_-FnOnce category functors (current)

Copied for reference. All following examples are in the same Functor-Applicative-Monad format without extra (sub)traits like WeakFunctor, Pure, ApplicativeLA2, etc. .

trait Functor {
    type F<'a, A: 'a>: 'a
    where
        Self: 'a;

    fn fmap<'a, A: 'a, B: 'a>(
        f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>,
    ) -> Self::F<'a, B>
    where
        Self: 'a;
}

fn fmap<'a, T: 'a + Functor, A: 'a, B: 'a>(
    f: impl 'a + FnOnce(A) -> B,
) -> impl FnOnce(T::F<'a, A>) -> T::F<'a, B> {
    |fa| T::fmap(f, fa)
}

Clone-Fn category functors

This is probably the closest representation to what Haskell views as a category of its types.

trait Functor: Clone {
    type F<'a, A: 'a + Clone>: 'a + Clone
    where
        Self: 'a;

    fn fmap<'a, A: 'a + Clone, B: 'a + Clone>(
        f: impl 'a + Clone + Fn(A) -> B, fa: Self::F<'a, A>,
    ) -> Self::F<'a, B>
    where
        Self: 'a;
}

fn fmap<'a, T: 'a + Functor, A: 'a + Clone, B: 'a + Clone>(
    f: impl 'a + Clone + Fn(A) -> B,
) -> impl 'a + Clone + Fn(T::F<'a, A>) -> T::F<'a, B> {
    move |fa| T::fmap(f.clone(), fa)
}

Clone-FnMut category functors

We view use of FnMut for category's morphisms as somewhat controversial1.

  • Use of direct/indirect mutable references is, arguably, counter-functional1.
  • Clone+FnMut is, generally, nonsensical1.
  • Due to that, morphisms category isn't a subcategory, so can't be wrapped.
  • Not being to wrap morphisms makes implementation of one specific Applicative method, sequential application (<*> in Haskell, seq in RADN) difficult.
trait Functor: Clone {
    type F<'a, A: 'a + Clone>: 'a + Clone
    where
        Self: 'a;

    fn fmap<'a, A: 'a + Clone, B: 'a + Clone>(
        f: impl 'a + FnMut(A) -> B, fa: Self::F<'a, A>,
    ) -> Self::F<'a, B>
    where
        Self: 'a;
}

Copy-Fn category functors

trait Functor: Copy {
    type F<'a, A: 'a + Copy>: 'a + Copy
    where
        Self: 'a;

    fn fmap<'a, A: 'a + Copy, B: 'a + Copy>(
        f: impl 'a + Copy + Fn(A) -> B, fa: Self::F<'a, A>,
    ) -> Self::F<'a, B>
    where
        Self: 'a;
}

fn fmap<'a, T: 'a + Functor, A: 'a + Copy, B: 'a + Copy>(
    f: impl 'a + Copy + Fn(A) -> B,
) -> impl 'a + Copy + Fn(T::F<'a, A>) -> T::F<'a, B> {
    move |fa| T::fmap(f, fa)
}

  1. elaborate? ↩︎