131 lines
4.7 KiB
Rust
131 lines
4.7 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 class_prelude;
|
|
pub mod context;
|
|
pub mod controlflow;
|
|
pub mod derivations;
|
|
mod extensions;
|
|
pub mod fail;
|
|
pub mod instances;
|
|
pub mod local;
|
|
pub mod shared;
|
|
#[cfg(test)]
|
|
pub mod test_suite;
|
|
#[cfg(test)]
|
|
pub mod tests;
|
|
pub mod weakfunctorany;
|
|
|
|
pub use self::applicative_select::{
|
|
ApplicativeSelect, ApplicativeSelectExt, Selected, SelectedWrapped,
|
|
};
|
|
use self::controlflow::{ControlFlow, Iterative};
|
|
pub use self::extensions::MonadExt;
|
|
#[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<'a>: 'a {
|
|
type F<A: '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 {}
|