func docs
This commit is contained in:
parent
4ad05fbe7c
commit
a5fef129fe
70
src/func.rs
70
src/func.rs
@ -1,3 +1,12 @@
|
||||
//! 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;
|
||||
pub mod copy_func;
|
||||
@ -7,13 +16,16 @@ pub mod test_suite;
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
|
||||
/// Part of Haskell's `Functor f` responsible to use `f a`.
|
||||
///
|
||||
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
|
||||
pub trait WeakFunctor {
|
||||
type F<'a, A: 'a>: 'a
|
||||
where
|
||||
Self: 'a;
|
||||
}
|
||||
|
||||
/// Rust-specific implementation of [Functor], respecting `move` semantics.
|
||||
/// Rust-specific implementation of [`Functor`], respecting `move` semantics.
|
||||
///
|
||||
/// Cannot insantiate for e.g. multi-element collections:
|
||||
/// ```compile_fail
|
||||
@ -33,7 +45,7 @@ pub trait WeakFunctor {
|
||||
/// ```
|
||||
/// 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
|
||||
///
|
||||
/// For Haskell-style Functors, use [clone_func::CloneFunctor] instead.
|
||||
/// For Haskell-style Functors, use [`clone_func::CloneFunctor`] instead.
|
||||
/// ```
|
||||
/// use radn_rs::func::clone_func::*;
|
||||
///
|
||||
@ -52,12 +64,17 @@ pub trait WeakFunctor {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
///
|
||||
/// <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,
|
||||
@ -65,6 +82,7 @@ pub trait Functor: WeakFunctor {
|
||||
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,
|
||||
@ -73,13 +91,9 @@ pub trait Functor: WeakFunctor {
|
||||
}
|
||||
}
|
||||
|
||||
pub 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> {
|
||||
move |fa| T::fmap(f, fa)
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
@ -88,7 +102,9 @@ pub trait ApplicativeSeq: Functor {
|
||||
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>,
|
||||
@ -98,15 +114,23 @@ pub trait ApplicativeLA2: Functor {
|
||||
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 [`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: Functor + ApplicativeSeq + ApplicativeLA2 + ApplicativeTuple {
|
||||
/// Equivalent of Haskell's `pure`/`return`.
|
||||
fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A>;
|
||||
|
||||
/// 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,
|
||||
@ -114,6 +138,7 @@ pub trait Applicative: Functor + ApplicativeSeq + ApplicativeLA2 + ApplicativeTu
|
||||
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,
|
||||
@ -122,7 +147,11 @@ pub trait Applicative: Functor + ApplicativeSeq + ApplicativeLA2 + ApplicativeTu
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 `>==`.
|
||||
fn bind<'a, A: 'a, B: 'a>(
|
||||
fa: Self::F<'a, A>,
|
||||
f: impl 'a + FnOnce(A) -> Self::F<'a, B>,
|
||||
@ -130,6 +159,7 @@ pub trait Monad: Applicative {
|
||||
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,
|
||||
@ -139,12 +169,28 @@ pub trait Monad: Applicative {
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent of Haskell's `MonadFail`.
|
||||
///
|
||||
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Monad.html>
|
||||
pub trait MonadFail<E>: Monad {
|
||||
fn fail<'a, A>(e: E) -> Self::F<'a, A>;
|
||||
/// Equivalent of Haskell's `fail`.
|
||||
fn fail<'a, A: 'a>(e: E) -> Self::F<'a, A>
|
||||
where
|
||||
Self: 'a;
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
fn empty<'a, A>() -> Self::F<'a, A>;
|
||||
/// Equivalent of Haskell's `empty`.
|
||||
fn empty<'a, A: 'a>() -> Self::F<'a, A>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn add<'a, A>(fa: Self::F<'a, A>, fb: Self::F<'a, A>) -> Self::F<'a, 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;
|
||||
}
|
||||
|
@ -1,3 +1,24 @@
|
||||
//! Implementation of some basic classes (in Haskell's meaning of a class).
|
||||
//!
|
||||
//! To get an understanding of what classes are about, see [`option`].
|
||||
//!
|
||||
//! For [`MonadFail<E>`] examples, see [`result`][^research].
|
||||
//!
|
||||
//! For the simplest form (even ChatGPT can understand it! lol) of [`Monad`], see [`solo`][^production].
|
||||
//!
|
||||
//! For async support, see [`future`][^production][^research].
|
||||
//!
|
||||
//! For "creative" execution models, see [`lazy`][^research] and [`stackless`][^research].
|
||||
//!
|
||||
//! To see when not to use [Monad]s, see [`composition`][^research].
|
||||
//!
|
||||
//! [^production]: classes expected to be used in production.
|
||||
//!
|
||||
//! [^research]: classes used for research purposes to enhance the abstract interfaces.
|
||||
|
||||
#[cfg(doc)]
|
||||
use crate::func::*;
|
||||
|
||||
pub mod composition;
|
||||
pub mod future;
|
||||
pub mod lazy;
|
||||
|
@ -1,3 +1,8 @@
|
||||
//! Async [Monad] based on [`Pin<Box<dyn Future>>`] (see: [`Pin`], [`Box::pin`], [`Future`]).
|
||||
//! This generally allows just using `.await` on wrapped instances.
|
||||
//!
|
||||
//! For sync, see [`super::solo`].
|
||||
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
use futures::join;
|
||||
|
@ -1,6 +1,15 @@
|
||||
//! Helper [Monad]s to defer execution until necessary.
|
||||
//! Wrapped value is just a box pointing to the constructor function.
|
||||
//!
|
||||
//! Due to semantical laziness,
|
||||
//! [`LazyClass::replace`] and [`LazyClass::discard_first`]/[`LazyClass::discard_second`]
|
||||
//! actually fully cancel the "unnecessary" computation.
|
||||
//!
|
||||
//! For stackless execution see [`super::stackless`].
|
||||
|
||||
use crate::func::*;
|
||||
|
||||
struct LazyClass;
|
||||
pub struct LazyClass;
|
||||
|
||||
impl WeakFunctor for LazyClass {
|
||||
type F<'a, A: 'a> = Box<dyn 'a + FnOnce() -> A>;
|
||||
|
@ -1,3 +1,12 @@
|
||||
//! Implementation of [`Monad`] for [`Option<A>`].
|
||||
//!
|
||||
//! If any of the input values are [`None`], you can expect the output to be [`None`] as well.
|
||||
//! That includes
|
||||
//! [`OptionClass::replace`] and [`OptionClass::discard_first`]/[`OptionClass::discard_second`],
|
||||
//! even if the value of the option would be ignored.
|
||||
//!
|
||||
//! For [`Result<A, E>`] alternative see [`super::result`]
|
||||
|
||||
use crate::func::*;
|
||||
|
||||
pub struct OptionClass;
|
||||
|
@ -1,3 +1,12 @@
|
||||
//! Implementation of [`MonadFail<E>`] for [`Result<A, E>`].
|
||||
//!
|
||||
//! If any of the input values are [`Err`], you can expect the output to be [`Err`] as well.
|
||||
//! That includes
|
||||
//! [`ResultClass::replace`] and [`ResultClass::discard_first`]/[`ResultClass::discard_second`],
|
||||
//! even if the value of the option would be ignored.
|
||||
//!
|
||||
//! For [`Option<A>`] alternative see [`super::option`]
|
||||
|
||||
use crate::func::*;
|
||||
|
||||
pub struct ResultClass<E: 'static>(E);
|
||||
@ -72,3 +81,12 @@ impl<E> Monad for ResultClass<E> {
|
||||
ffa?
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> MonadFail<E> for ResultClass<E> {
|
||||
fn fail<'a, A: 'a>(e: E) -> Self::F<'a, A>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
//! Simplest sync [Monad].
|
||||
//!
|
||||
//! For async, see [`super::future`].
|
||||
|
||||
use crate::func::*;
|
||||
|
||||
pub struct SoloClass;
|
||||
|
@ -1,3 +1,8 @@
|
||||
//! Helper [Monad]s to move deep execution chains off the stack onto the heap.
|
||||
//! [`Stackless<A>`] represents a wrapped value.
|
||||
//!
|
||||
//! For lazy stackful execution see [`super::lazy`].
|
||||
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
use crate::func::derivations::*;
|
||||
@ -50,7 +55,9 @@ impl<'a, A: 'a> Stackless<'a, A> {
|
||||
self.0(Box::new(f))
|
||||
}
|
||||
|
||||
fn bind<B: 'a>(self, f: impl 'a + FnOnce(A) -> Stackless<'a, B>) -> Stackless<'a, B> {
|
||||
/// Method-like equivalent of [`Monad::bind`],
|
||||
/// the preferred way to chain [`Stackless<A>`] and `FnOnce(A) -> Stackless<B>` into [`Stackless<B>`].
|
||||
pub fn bind<B: 'a>(self, f: impl 'a + FnOnce(A) -> Stackless<'a, B>) -> Stackless<'a, B> {
|
||||
Stackless(Box::new(|takesb| {
|
||||
let lcell = Rc::new(Cell::new(None));
|
||||
let rcell = lcell.clone();
|
||||
@ -66,7 +73,8 @@ impl<'a, A: 'a> Stackless<'a, A> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn map<B: 'a>(self, f: impl 'a + FnOnce(A) -> B) -> Stackless<'a, B> {
|
||||
/// Method-like equivalent of [`Functor::fmap`].
|
||||
pub fn map<B: 'a>(self, f: impl 'a + FnOnce(A) -> B) -> Stackless<'a, B> {
|
||||
Stackless(Box::new(|takesb| {
|
||||
let lcell = Rc::new(Cell::new(None));
|
||||
let rcell = lcell.clone();
|
||||
@ -85,6 +93,8 @@ impl<'a, A: 'a> Stackless<'a, A> {
|
||||
}))
|
||||
}
|
||||
|
||||
/// Evaluate. Process is loop-like on the inside
|
||||
/// with the least amount of recursion the current model allows to use.
|
||||
pub fn evaluate(self) -> A {
|
||||
let ocell = Rc::new(Cell::new(None));
|
||||
let icell = ocell.clone();
|
||||
|
@ -1,3 +1,9 @@
|
||||
//! Equivalent of [`crate::func`] for [`Clone`]/[`Fn`] Category.
|
||||
//! Similar to what you'd encounter in Haskell.
|
||||
//! Not well maintained due to not being used in the main RADN code base.
|
||||
//!
|
||||
//! See also: [`super::copy_func`]
|
||||
|
||||
pub trait CloneWeakFunctor {
|
||||
type ClF<'a, A: Clone>: Clone;
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
//! Equivalent of [`crate::func`] for [`Copy`]/[`Fn`] Category.
|
||||
//! Not well maintained due to not being used in the main RADN code base.
|
||||
//!
|
||||
//! See also: [`super::clone_func`]
|
||||
|
||||
pub trait CopyWeakFunctor {
|
||||
type CF<'a, A: Copy>: Copy;
|
||||
}
|
||||
|
@ -1,5 +1,14 @@
|
||||
//! Useful helper functions/methods to extrapolate the existing behaviour.
|
||||
|
||||
use crate::func::*;
|
||||
|
||||
/// Equivalent of Haskell's `fmap`. `function-function` equivalent of [Functor::fmap].
|
||||
pub 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> {
|
||||
move |fa| T::fmap(f, fa)
|
||||
}
|
||||
|
||||
pub trait ApplicativeLA2ViaSeq: ApplicativeSeq {
|
||||
fn _la2_via_seq<'a, A: 'a, B: 'a, C: 'a>(
|
||||
f: impl 'a + FnOnce(A, B) -> C,
|
||||
|
@ -3,7 +3,8 @@ use super::{tests::*, *};
|
||||
pub trait FunctorTestSuite: WeakFunctor + Eqr {
|
||||
fn sample<'a, A: 'a, F: FnMut(&'a dyn Fn(A) -> Self::F<'a, A>)>(f: F)
|
||||
where
|
||||
Self::F<'a, A>: 'a, Self: 'a;
|
||||
Self::F<'a, A>: 'a,
|
||||
Self: 'a;
|
||||
}
|
||||
|
||||
pub fn functor_follows_laws<T: Functor + FunctorTestSuite>() -> R {
|
||||
|
@ -5,14 +5,14 @@ use std::{error::Error, marker::PhantomData, rc::Rc};
|
||||
|
||||
use crate::core::*;
|
||||
|
||||
/// This trait combines functionality of [Mentionable] and [Factory],
|
||||
/// while limiting [Mentionable::points] (and corresponding [Mentionable::topology]) to an empty sequence.
|
||||
/// This trait combines functionality of [`Mentionable`] and [`Factory`],
|
||||
/// while limiting [`Mentionable::points`] (and corresponding [`Mentionable::topology`]) to an empty sequence.
|
||||
pub trait Atomic: 'static + Sized + Clone + Serializable {
|
||||
/// Equivalent of [Factory::ParseError].
|
||||
/// Equivalent of [`Factory::ParseError`].
|
||||
type ParseError: Error;
|
||||
/// Static equivalent of [Factory::deserialize].
|
||||
/// Static equivalent of [`Factory::deserialize`].
|
||||
fn deserialize(deserializer: &mut dyn Deserializer) -> Result<Self, Self::ParseError>;
|
||||
/// Static equivalent of [Factory::unexpected_tail].
|
||||
/// Static equivalent of [`Factory::unexpected_tail`].
|
||||
fn unexpected_tail(tail: &[u8]) -> Self::ParseError;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! This module introduces [Option]-like concepts into RADN typesystem using [Nullable].
|
||||
//! This module introduces [`Option`]-like concepts into RADN typesystem using [`Nullable`].
|
||||
|
||||
use crate::core::*;
|
||||
use crate::std::*;
|
||||
|
Loading…
Reference in New Issue
Block a user