radn-rs/src/func.rs
2023-05-26 08:05:53 +00:00

391 lines
12 KiB
Rust

//! Generic functional concepts implemented in Rust.
//! Some choices are intentionally less generic due to specifics of the domain.
//! That, for example, includes the almost exclusive focus on [`FnOnce`] category.
//!
//! Sources:
//! * <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
//! * <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Applicative.html>
//! * <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
mod applicative_select;
pub mod clone_func;
mod controlflow;
pub mod copy_func;
pub mod derivations;
pub mod instances;
mod speculative;
#[cfg(test)]
pub mod test_suite;
#[cfg(test)]
pub mod tests;
pub use std::ops::ControlFlow;
pub use radn_derive::{CovariantFunctor, SharedFunctor};
pub use self::applicative_select::{
ApplicativeSelect, ApplicativeSelectExt, Selected, SelectedWrapped,
};
use self::controlflow::{BindableMut, ControlFlowInstance};
pub use self::controlflow::{Iterative, IterativeWrapped};
#[cfg(doc)]
use self::instances::stackless::StacklessInstance;
/// Part of Haskell's `Functor f` responsible for having `f a`.
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
pub trait WeakFunctor {
/// Type of the wrapped value.
type F<'a, A: 'a>: 'a
where
Self: 'a;
}
pub trait WeakFunctorA<'a>: 'a {
type Fa<A: 'a>: 'a;
}
impl<'a, T: 'a + WeakFunctor> WeakFunctorA<'a> for T {
type Fa<A: 'a> = T::F<'a, A>;
}
pub type Wrap<'a, A, T> = <T as WeakFunctor>::F<'a, A>;
/// Rust-specific implementation of [`Functor`], respecting `move` semantics.
///
/// Cannot insantiate for e.g. multi-element collections:
/// ```compile_fail
/// use radn_rs::func::*;
///
/// struct VecInstance;
///
/// impl WeakFunctor for VecInstance {
/// type F<'a, A> = Vec<A>;
/// }
///
/// impl Functor for VecInstance {
/// fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> {
/// fa.into_iter().map(f).collect()
/// }
/// }
/// ```
/// Why does it fail to compile? `.map` expects `FnMut` (or we can think of it being `Fn`, doesn't matter here).
/// But what we provide it (`f`) is only `FnOnce`.
///
/// For Haskell-style Functors, use [`clone_func::CloneFunctor`] instead.
/// ```
/// use radn_rs::func::clone_func::*;
///
/// struct VecInstance;
///
/// impl CloneWeakFunctor for VecInstance {
/// type ClF<'a, A: Clone> = Vec<A>;
/// }
///
/// impl CloneFunctor for VecInstance {
/// fn clone_fmap<'a, A: 'a + Clone, B: 'a + Clone>(
/// f: impl 'a + Fn(A) -> B,
/// fa: Self::ClF<'a, A>,
/// ) -> Self::ClF<'a, B> {
/// fa.into_iter().map(f).collect()
/// }
/// }
/// ```
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
pub trait Functor: WeakFunctor {
/// Equivalent or Haskell's `fmap`.
/// Due to Rust limitations, it's not a `function->function` conversion.
/// For that see [`derivations::fmap`].
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;
/// Equivalent of Haskell's `$>`/`<$`.
fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B>
where
Self: 'a,
{
Self::fmap(|_| b, fa)
}
/// Equivalent of Haskell's `void`.
fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()>
where
Self: 'a,
{
Self::replace(fa, ())
}
}
/// Part of [`Applicative`] responsible for Haskell's value lifting, `pure`.
pub trait Pure: Functor {
/// Equivalent of Haskell's `pure`/`return`.
fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A>
where
Self: 'a;
}
/// Part of [`Applicative`] responsible for Haskell's sequential application `<*>`.
pub trait ApplicativeSeq: Functor {
/// Equivalent of Haskell's `<*>`.
fn seq<'a, A: 'a, B: 'a>(
ff: Self::F<'a, impl 'a + FnOnce(A) -> B>,
fa: Self::F<'a, A>,
) -> Self::F<'a, B>
where
Self: 'a;
}
/// Part of [`Applicative`] responsible for Haskell's result combination `listA2`.
pub trait ApplicativeLA2: Functor {
/// Equivalent of Haskell's `listA2`.
fn la2<'a, A: 'a, B: 'a, C: 'a>(
f: impl 'a + FnOnce(A, B) -> C,
fa: Self::F<'a, A>,
fb: Self::F<'a, B>,
) -> Self::F<'a, C>
where
Self: 'a;
}
/// Part of [`Applicative`] responsible for Rust-style result combination, specifically for tuples.
pub trait ApplicativeTuple: Functor {
/// Similar to Haskell's `listA2` but with [Iterator::collect]-ish semantics.
fn tuple<'a, A: 'a, B: 'a>(fab: (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)>
where
Self: 'a;
}
/// Equivalent of Haskell's `Applicative`.
/// Split into [`Pure`], [`ApplicativeSeq`], [`ApplicativeLA2`] and [`ApplicativeTuple`] due to Rust limitations.
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Applicative.html>
pub trait Applicative:
Pure + ApplicativeSeq + ApplicativeLA2 + ApplicativeTuple + ApplicativeSelect
{
/// Equivalent of Haskell's `*>`/`>>`.
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where
Self: 'a,
{
Self::seq(Self::replace(fa, |b| b), fb)
}
/// Equivalent of Haskell's `<*`.
fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A>
where
Self: 'a,
{
Self::la2(|a, _| a, fa, fb)
}
}
/// Equivalent of Haskell's `Monad`.
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
pub trait Monad: Applicative {
/// Equivalent of Haskell's `>==`.
/// Due to Rust limitations, it's not a `function->function` conversion.
/// For that see [`derivations::bind`].
fn bind<'a, A: 'a, B: 'a>(
fa: Self::F<'a, A>,
f: impl 'a + FnOnce(A) -> Self::F<'a, B>,
) -> Self::F<'a, B>
where
Self: 'a;
/// Included for optimisation and clarity.
/// Generally, [`Monad::bind`] should be enough implement it.
/// See [`StacklessInstance::iterate`] for a generic, though less-than ideal, blanket implementation.
/// On practice, you generally shouldn't be using [`Monad::bind`]/[`Pure::pure`]/[`Functor::fmap`] here.
fn iterate<'a, B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B>
where
Self: 'a;
/// Equivalent of Haskell's `join`.
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
where
Self: 'a,
{
Self::bind(ffa, |fa| fa)
}
}
pub trait MonadExt<'a>: 'a + Monad {
/// [`FnMut`] version of [`Monad::iterate`].
/// Reasoning for this method existing at all is that
/// most usecases are better modelled with [`FnMut`]
/// rather than some dedicated state type.
fn iterate_mut<A: 'a, B: 'a>(
a: A,
f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow<B, A>>,
) -> Self::F<'a, B> {
Self::iterate(BindableMut::new(a, f))
}
}
impl<'a, T: 'a + Monad> MonadExt<'a> for T {}
/// Part of [`MonadFail`] responsible for Haskell's `fail`.
pub trait Fail<E>: WeakFunctor {
/// Equivalent of Haskell's `fail`.
fn fail<'a, A: 'a>(e: E) -> Self::F<'a, A>
where
Self: 'a,
E: 'a;
}
/// Equivalent of Haskell's `MonadFail`. Auto-implemented for all [`Fail`]`+`[`Monad`].
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
pub trait MonadFail<E>: Monad + Fail<E> {}
impl<E, T: Monad + Fail<E>> MonadFail<E> for T {}
/// Represents wrapped results which are instantly available.
pub trait LocalFunctor: WeakFunctor {
/// Extract iteration state, if successful.
fn unstuff<'a, A: 'a, B: 'a>(
state: Self::F<'a, ControlFlow<B, A>>,
) -> ControlFlow<Self::F<'a, B>, A>
where
Self: 'a,
{
Self::stuff::<_, ControlFlowInstance<A>>(state)
}
/// Stuff wrapped result into another functor.
fn stuff<'a, A: 'a, T: 'a + Pure>(fa: Self::F<'a, T::F<'a, A>>) -> T::F<'a, Self::F<'a, A>>
where
Self: 'a;
}
/// Represents a (collection of) [Monad]\(s) that can hold any type of error.
pub trait MonadFailAny {
/// [`MonadFail`] for a specific error type.
type W<E>: MonadFail<E>;
/// Associated infallible [`Monad`].
type T: Monad;
fn unstuff<'a, A: 'a, E: 'a>(wa: WrapE<'a, A, E, Self>) -> Wrap<'a, Result<A, E>, Self::T>
where
Self: 'a;
fn stuff<'a, A: 'a, E: 'a>(fa: Wrap<'a, Result<A, E>, Self::T>) -> WrapE<'a, A, E, Self>
where
Self: 'a;
/// Equivalent of [`Result::map_err`].
fn map_err<'a, A: 'a, E0: 'a, E1: 'a>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + FnOnce(E0) -> E1,
) -> WrapE<'a, A, E1, Self>
where
Self: 'a,
{
Self::bind_err(wa, |e0| Self::fail(f(e0)))
}
/// Equivalent of `catch`/`except`. To inject errors on success, see [`MonadFailAny::bind`].
fn bind_err<'a, A: 'a, E0: 'a, E1: 'a>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + FnOnce(E0) -> WrapE<'a, A, E1, Self>,
) -> WrapE<'a, A, E1, Self>
where
Self: 'a,
{
Self::bind(wa, |result| match result {
Ok(a) => Self::pure(a),
Err(e0) => f(e0),
})
}
/// Bind the result, an equivalent of `catch`/`except` with ability to "raise" extra errors
/// on success too, unlike [`MonadFailAny::bind_err`].
///
/// Note: Reasonably it is expected to lack fail semantics for the underlying result.
/// Therefore the default implementation descends into the non-fail monad [`MonadFailAny::T`].
fn bind<'a, A: 'a, B: 'a, E0: 'a, E1: 'a>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + FnOnce(Result<A, E0>) -> WrapE<'a, B, E1, Self>,
) -> WrapE<'a, B, E1, Self>
where
Self: 'a,
{
Self::stuff(<Self::T as Monad>::bind(Self::unstuff(wa), |result| {
Self::unstuff(f(result))
}))
}
/// Equivalent of [`Monad::join`], flattening the errors.
///
/// Note: default implementation doesn't depend on [`Monad::join`].
fn join<'a, A: 'a, E0: 'a, E1: 'a>(
wwa: WrapE<'a, WrapE<'a, A, E0, Self>, E1, Self>,
) -> WrapE<'a, A, Result<E0, E1>, Self>
where
Self: 'a,
{
Self::bind(wwa, |result| match result {
Ok(wa) => Self::map_err(wa, Ok),
Err(e1) => Self::fail(Err(e1)),
})
}
/// Lift the error.
fn rotate_out<'a, A: 'a, E0: 'a, E1: 'a>(
wa: WrapE<'a, Result<A, E1>, E0, Self>,
) -> WrapE<'a, A, Result<E1, E0>, Self>
where
Self: 'a,
{
<Self::W<Result<E1, E0>> as Monad>::bind(Self::map_err(wa, Err), |fa| match fa {
Ok(a) => Self::pure(a),
Err(e) => Self::fail(Ok(e)),
})
}
}
pub type WrapE<'a, A, E, Fallible> = Wrap<'a, A, <Fallible as MonadFailAny>::W<E>>;
pub trait MonadFailAnyExt<'a>: 'a + MonadFailAny {
fn pure<E: 'a, A: 'a>(a: A) -> WrapE<'a, A, E, Self> {
<Self::W<E> as Pure>::pure(a)
}
fn fail<E: 'a, A: 'a>(e: E) -> WrapE<'a, A, E, Self> {
<Self::W<E> as Fail<E>>::fail(e)
}
fn speculative<A: 'a, B: 'a, E0: 'a, E1: 'a>(
wwa: WrapE<'a, WrapE<'a, A, E0, Self>, E1, Self>,
wwb: WrapE<'a, WrapE<'a, B, E0, Self>, E1, Self>,
) -> WrapE<'a, (A, B), Result<E0, E1>, Self> {
<Self as speculative::SpeculativeFail<'a>>::speculative(wwa, wwb)
}
}
impl<'a, Fallible: ?Sized + 'a + MonadFailAny> MonadFailAnyExt<'a> for Fallible {}
pub trait SharedFunctor: WeakFunctor {
type Shared<'a, A: 'a + Clone>: 'a + Clone
where
Self: 'a;
fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A>
where
Self: 'a;
fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A>
where
Self: 'a;
}
pub trait CovariantFunctor: WeakFunctor {
fn variate<'a: 'b, 'b, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'b, A>
where
Self: 'a;
}