347 lines
11 KiB
Rust
347 lines
11 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>
|
|
|
|
pub mod classes;
|
|
pub mod clone_func;
|
|
mod controlflow;
|
|
pub mod copy_func;
|
|
pub mod derivations;
|
|
#[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::controlflow::{AIterative, AIterativeWrapped, Iterative, IterativeWrapped};
|
|
use self::controlflow::{ArgumentedIterative, BindableMut, ControlFlowClass};
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Rust-specific implementation of [`Functor`], respecting `move` semantics.
|
|
///
|
|
/// Cannot insantiate for e.g. multi-element collections:
|
|
/// ```compile_fail
|
|
/// use radn_rs::func::*;
|
|
///
|
|
/// struct VecClass;
|
|
///
|
|
/// impl WeakFunctor for VecClass {
|
|
/// type F<'a, A> = Vec<A>;
|
|
/// }
|
|
///
|
|
/// impl Functor for VecClass {
|
|
/// 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 VecClass;
|
|
///
|
|
/// impl CloneWeakFunctor for VecClass {
|
|
/// type ClF<'a, A: Clone> = Vec<A>;
|
|
/// }
|
|
///
|
|
/// impl CloneFunctor for VecClass {
|
|
/// 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 {
|
|
/// 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;
|
|
|
|
/// Simplified, [`FnMut`] version of [`Monad::iterate_argument`].
|
|
/// Reasoning for this method existing at all is that
|
|
/// most usecases are better modelled with [`FnMut`]
|
|
/// rather than some dedicated state type.
|
|
///
|
|
/// Note: hypothetically, you can implement [`Monad::iterate_argument`] from [`Monad::iterate_mut`],
|
|
/// but it's highly discouraged.
|
|
fn iterate_mut<'a, A: 'a, B: 'a>(
|
|
a: A,
|
|
f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow<B, A>>,
|
|
) -> Self::F<'a, B>
|
|
where
|
|
Self: 'a,
|
|
{
|
|
Self::iterate_argument(a, BindableMut::new(f))
|
|
}
|
|
|
|
/// Kleisli category composition special case used to represent loops.
|
|
/// Included for optimisation and clarity.
|
|
/// Generally, [`Monad::bind`] should be enough implement it.
|
|
/// See [`classes::stackless::StacklessClass::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_argument<'a, A: 'a, B: 'a>(
|
|
a: A,
|
|
f: impl AIterative<'a, T = Self, A = A, B = B>,
|
|
) -> Self::F<'a, B>
|
|
where
|
|
Self: 'a,
|
|
{
|
|
Self::iterate(ArgumentedIterative(a, f))
|
|
}
|
|
|
|
/// Iteration without composition semantics of [`Monad::iterate_argument`].
|
|
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::F<'a, A>: 'a,
|
|
Self: 'a,
|
|
{
|
|
Self::bind(ffa, |fa| fa)
|
|
}
|
|
}
|
|
|
|
/// 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 {}
|
|
|
|
/// Equivalent of Haskell's `Alternative`.
|
|
/// Lacks `some`/`many` definitions due to [`FnOnce`] category semantics.
|
|
///
|
|
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Applicative.html>
|
|
pub trait Alternative: Applicative {
|
|
/// Equivalent of Haskell's `empty`.
|
|
fn empty<'a, A: 'a>() -> Self::F<'a, A>
|
|
where
|
|
Self: 'a;
|
|
|
|
/// Equivalent of Haskell's `<|>`.
|
|
fn add<'a, A: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, A>) -> Self::F<'a, A>
|
|
where
|
|
Self: 'a;
|
|
}
|
|
|
|
/// 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::<_, ControlFlowClass<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>;
|
|
|
|
/// Equivalent of [`Result::map_err`].
|
|
fn map_err<'a, A: 'a, E0: 'a, E1: 'a>(
|
|
wa: <Self::W<E0> as WeakFunctor>::F<'a, A>,
|
|
f: impl 'a + FnOnce(E0) -> E1,
|
|
) -> <Self::W<E1> as WeakFunctor>::F<'a, A>
|
|
where
|
|
Self: 'a;
|
|
|
|
fn bind_err<'a, A: 'a, E0: 'a, E1: 'a>(
|
|
wa: <Self::W<E0> as WeakFunctor>::F<'a, A>,
|
|
f: impl 'a + FnOnce(E0) -> <Self::W<E1> as WeakFunctor>::F<'a, A>,
|
|
) -> <Self::W<E1> as WeakFunctor>::F<'a, A>
|
|
where
|
|
Self: 'a;
|
|
|
|
fn rotate_out<'a, A: 'a, E0: 'a, E1: 'a>(
|
|
wa: <Self::W<E0> as WeakFunctor>::F<'a, Result<A, E1>>,
|
|
) -> <Self::W<Result<E1, E0>> as WeakFunctor>::F<'a, A>
|
|
where
|
|
Self: 'a,
|
|
{
|
|
<Self::W<Result<E1, E0>> as Monad>::bind(Self::map_err(wa, Err), |fa| match fa {
|
|
Ok(a) => <Self::W<Result<E1, E0>> as Pure>::pure(a),
|
|
Err(e) => <Self::W<Result<E1, E0>> as Fail<Result<E1, E0>>>::fail(Ok(e)),
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Represents a (collection of) [Monad]\(s),
|
|
/// wrapped values of which are interchangeable with another [Monad]'s
|
|
/// wrapped [Result]s.
|
|
pub trait MonadFailOver<T: Monad>: MonadFailAny {
|
|
fn unstuff<'a, A: 'a, E: 'a>(
|
|
wa: <Self::W<E> as WeakFunctor>::F<'a, A>,
|
|
) -> <T as WeakFunctor>::F<'a, Result<A, E>>
|
|
where
|
|
Self: 'a,
|
|
T: 'a;
|
|
|
|
fn stuff<'a, A: 'a, E: 'a>(
|
|
fa: <T as WeakFunctor>::F<'a, Result<A, E>>,
|
|
) -> <Self::W<E> as WeakFunctor>::F<'a, A>
|
|
where
|
|
Self: 'a,
|
|
T: 'a;
|
|
}
|
|
|
|
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;
|
|
}
|