242 lines
8.6 KiB
Rust
242 lines
8.6 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;
|
|
pub mod context;
|
|
mod controlflow;
|
|
pub mod copy_func;
|
|
pub mod derivations;
|
|
mod extensions;
|
|
pub mod instances;
|
|
mod shared;
|
|
#[cfg(test)]
|
|
pub mod test_suite;
|
|
#[cfg(test)]
|
|
pub mod tests;
|
|
|
|
pub use std::ops::ControlFlow;
|
|
|
|
pub use radn_derive::SharedFunctorAny;
|
|
|
|
pub use self::applicative_select::{
|
|
ApplicativeSelect, ApplicativeSelectExt, Selected, SelectedWrapped,
|
|
};
|
|
use self::controlflow::{BindableMut, ControlFlowInstance};
|
|
pub use self::controlflow::{Iterative, IterativeWrapped};
|
|
pub use self::extensions::{MonadExt, MonadFailAnyExt};
|
|
#[cfg(doc)]
|
|
use self::instances::stackless::StacklessInstance;
|
|
pub use self::shared::{SharedFunctor, SharedFunctorAny};
|
|
|
|
pub trait WeakFunctorAny {
|
|
/// Type of the wrapped value.
|
|
type FAny<'a, A: 'a>: 'a
|
|
where
|
|
Self: 'a;
|
|
}
|
|
|
|
/// 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<'a>: 'a {
|
|
type F<A: 'a>: 'a;
|
|
}
|
|
|
|
impl<'a, T: ?Sized + 'a + WeakFunctorAny> WeakFunctor<'a> for T {
|
|
type F<A: 'a> = T::FAny<'a, A>;
|
|
}
|
|
|
|
pub type Wrap<'a, A, T> = <T as WeakFunctor<'a>>::F<A>;
|
|
|
|
/// Rust-specific implementation of [`Functor`], respecting `move` semantics.
|
|
///
|
|
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
|
|
pub trait Functor<'a>: WeakFunctor<'a> {
|
|
/// 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, B: 'a>(fa: Self::F<A>, f: impl 'a + FnOnce(A) -> B) -> Self::F<B>;
|
|
|
|
/// Equivalent of Haskell's `$>`/`<$`.
|
|
fn replace<A: 'a, B: 'a>(fa: Self::F<A>, b: B) -> Self::F<B> {
|
|
Self::fmap(fa, |_| b)
|
|
}
|
|
|
|
/// Equivalent of Haskell's `void`.
|
|
fn void<A: 'a>(fa: Self::F<A>) -> Self::F<()> {
|
|
Self::replace(fa, ())
|
|
}
|
|
}
|
|
|
|
/// Part of [`Applicative`] responsible for Haskell's value lifting, `pure`.
|
|
pub trait Pure<'a>: Functor<'a> {
|
|
/// Equivalent of Haskell's `pure`/`return`.
|
|
fn pure<A: 'a>(a: A) -> Self::F<A>;
|
|
}
|
|
|
|
/// Part of [`Applicative`] responsible for Haskell's sequential application `<*>`.
|
|
pub trait ApplicativeSeq<'a>: Functor<'a> {
|
|
/// Equivalent of Haskell's `<*>`.
|
|
fn seq<A: 'a, B: 'a>(ff: Self::F<impl 'a + FnOnce(A) -> B>, fa: Self::F<A>) -> Self::F<B>;
|
|
}
|
|
|
|
/// Part of [`Applicative`] responsible for Haskell's result combination `listA2`.
|
|
pub trait ApplicativeLA2<'a>: Functor<'a> {
|
|
/// Equivalent of Haskell's `listA2`.
|
|
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>;
|
|
}
|
|
|
|
/// Part of [`Applicative`] responsible for Rust-style result combination, specifically for tuples.
|
|
pub trait ApplicativeTuple<'a>: Functor<'a> {
|
|
/// Similar to Haskell's `listA2` but with [Iterator::collect]-ish semantics.
|
|
fn tuple<A: 'a, B: 'a>(fab: (Self::F<A>, Self::F<B>)) -> Self::F<(A, B)>;
|
|
}
|
|
|
|
/// 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<'a>:
|
|
Pure<'a> + ApplicativeSeq<'a> + ApplicativeLA2<'a> + ApplicativeTuple<'a> + ApplicativeSelect<'a>
|
|
{
|
|
/// Equivalent of Haskell's `*>`/`>>`.
|
|
fn discard_first<A: 'a, B: 'a>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<B> {
|
|
Self::seq(Self::replace(fa, |b| b), fb)
|
|
}
|
|
|
|
/// Equivalent of Haskell's `<*`.
|
|
fn discard_second<A: 'a, B: 'a>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<A> {
|
|
Self::la2(fa, fb, |a, _| a)
|
|
}
|
|
}
|
|
|
|
/// Equivalent of Haskell's `Monad`.
|
|
///
|
|
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
|
|
pub trait Monad<'a>: Applicative<'a> {
|
|
/// Equivalent of Haskell's `>==`.
|
|
/// Due to Rust limitations, it's not a `function->function` conversion.
|
|
/// For that see [`derivations::bind`].
|
|
fn bind<A: 'a, B: 'a>(fa: Self::F<A>, f: impl 'a + FnOnce(A) -> Self::F<B>) -> Self::F<B>;
|
|
|
|
/// 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<B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<B>;
|
|
|
|
/// Equivalent of Haskell's `join`.
|
|
fn join<A: 'a>(ffa: Self::F<Self::F<A>>) -> Self::F<A> {
|
|
Self::bind(ffa, |fa| fa)
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Monad<'a>> MonadExt<'a> for T {}
|
|
|
|
/// Part of [`MonadFail`] responsible for Haskell's `fail`.
|
|
pub trait Fail<'a, E: 'a>: WeakFunctor<'a> {
|
|
/// Equivalent of Haskell's `fail`.
|
|
fn fail<A: 'a>(e: E) -> Self::F<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<'a, E: 'a>: Monad<'a> + Fail<'a, E> {}
|
|
|
|
impl<'a, E: 'a, T: Monad<'a> + Fail<'a, E>> MonadFail<'a, E> for T {}
|
|
|
|
/// Represents wrapped results which are instantly available.
|
|
pub trait LocalFunctor<'a>: WeakFunctor<'a> {
|
|
/// Extract iteration state, if successful.
|
|
fn unstuff<A: 'a, B: 'a>(state: Self::F<ControlFlow<B, A>>) -> ControlFlow<Self::F<B>, A> {
|
|
Self::stuff::<_, ControlFlowInstance<A>>(state)
|
|
}
|
|
|
|
/// Stuff wrapped result into another functor.
|
|
fn stuff<A: 'a, T: Pure<'a>>(fa: Self::F<T::F<A>>) -> T::F<Self::F<A>>;
|
|
}
|
|
|
|
/// Represents a (collection of) [Monad]\(s) that can hold any type of error.
|
|
pub trait MonadFailAny<'a>: 'a {
|
|
/// [`MonadFail`] for a specific error type.
|
|
type W<E>: MonadFail<'a, E>
|
|
where
|
|
E: 'a;
|
|
|
|
/// Associated infallible [`Monad`].
|
|
type T: Monad<'a>;
|
|
|
|
fn unstuff<A: 'a, E: 'a>(wa: WrapE<'a, A, E, Self>) -> Wrap<'a, Result<A, E>, Self::T>;
|
|
|
|
fn stuff<A: 'a, E: 'a>(fa: Wrap<'a, Result<A, E>, Self::T>) -> WrapE<'a, A, E, Self>;
|
|
|
|
/// Equivalent of [`Result::map_err`].
|
|
fn map_err<A: 'a, E0: 'a, E1: 'a>(
|
|
wa: WrapE<'a, A, E0, Self>,
|
|
f: impl 'a + FnOnce(E0) -> E1,
|
|
) -> WrapE<'a, A, E1, Self> {
|
|
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, 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> {
|
|
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, 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> {
|
|
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, E0: 'a, E1: 'a>(
|
|
wwa: WrapE<'a, WrapE<'a, A, E0, Self>, E1, Self>,
|
|
) -> WrapE<'a, A, Result<E0, E1>, Self> {
|
|
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, E0: 'a, E1: 'a>(
|
|
wa: WrapE<'a, Result<A, E1>, E0, Self>,
|
|
) -> WrapE<'a, A, Result<E1, E0>, Self> {
|
|
<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<'a>>::W<E>>;
|