From 1a5e9f15f393599e83c644862b823eda77c26517 Mon Sep 17 00:00:00 2001 From: timofey Date: Mon, 24 Apr 2023 17:21:36 +0000 Subject: [PATCH] Pure + LocalFunctor --- src/func.rs | 28 ++++++++++--- src/func/classes/composition.rs | 71 ++++++++++++++++++++++++++++++++- src/func/classes/future.rs | 10 +++-- src/func/classes/lazy.rs | 10 +++-- src/func/classes/option.rs | 10 +++-- src/func/classes/result.rs | 10 +++-- src/func/classes/solo.rs | 10 +++-- src/func/classes/stackless.rs | 10 +++-- src/std/tracing.rs | 10 +++-- src/testing/counted.rs | 10 +++-- 10 files changed, 140 insertions(+), 39 deletions(-) diff --git a/src/func.rs b/src/func.rs index da47149..d87c00f 100644 --- a/src/func.rs +++ b/src/func.rs @@ -91,6 +91,14 @@ pub trait Functor: WeakFunctor { } } +/// 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 `<*>`. @@ -123,13 +131,10 @@ pub trait ApplicativeTuple: Functor { } /// Equivalent of Haskell's `Applicative`. -/// Split into [`ApplicativeSeq`], [`ApplicativeLA2`] and [`ApplicativeTuple`] due to Rust limitations. +/// Split into [`Pure`], [`ApplicativeSeq`], [`ApplicativeLA2`] and [`ApplicativeTuple`] due to Rust limitations. /// /// -pub trait Applicative: Functor + ApplicativeSeq + ApplicativeLA2 + ApplicativeTuple { - /// Equivalent of Haskell's `pure`/`return`. - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A>; - +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 @@ -214,3 +219,16 @@ pub trait Alternative: Applicative { 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, IState>) -> IState> + where + Self: 'a; + + /// Stuff wrapped result into another functor. + fn stuff<'a, A: 'a, U: 'a + Functor>(fa: Self::F<'a, U::F<'a, A>>) -> U::F<'a, Self::F<'a, A>> + where + Self: 'a; +} diff --git a/src/func/classes/composition.rs b/src/func/classes/composition.rs index d04e938..e2775be 100644 --- a/src/func/classes/composition.rs +++ b/src/func/classes/composition.rs @@ -1,9 +1,9 @@ use crate::func::*; -struct CompositionClass(U, V); +pub struct CompositionClass(U, V); impl WeakFunctor for CompositionClass { - type F<'a, A: 'a> = U::F<'a, V::F<'a, A>> where U: 'a, V: 'a; + type F<'a, A: 'a> = U::F<'a, V::F<'a, A>> where Self: 'a; } impl Functor for CompositionClass { @@ -29,6 +29,15 @@ impl Functor for CompositionClass { } } +impl Pure for CompositionClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> + where + Self: 'a, + { + U::pure(V::pure(a)) + } +} + impl ApplicativeSeq for CompositionClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -53,3 +62,61 @@ impl ApplicativeLA2 for CompositionClass ApplicativeTuple for CompositionClass { + fn tuple<'a, A: 'a, B: 'a>(fab: (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> + where + Self: 'a, + { + U::fmap(V::tuple, U::tuple(fab)) + } +} + +impl Applicative for CompositionClass { + 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, + { + U::la2(|ua, ub| V::discard_first(ua, ub), fa, fb) + } + + 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, + { + U::la2(|ua, ub| V::discard_second(ua, ub), fa, fb) + } +} + +impl Monad for CompositionClass { + 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, + { + U::bind(fa, |ua| U::fmap(V::join, V::stuff::<_, U>(V::fmap(f, ua)))) + } + + fn ibind<'a, A: 'a, B: 'a>( + a: A, + mut f: impl 'a + FnMut(A) -> Self::F<'a, IState>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + U::ibind(a, move |a| { + let fx = f(a); + U::fmap(|ustate| V::unstuff(ustate), fx) + }) + } + + 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, + { + U::join(U::fmap(|ufa| U::fmap(V::join, V::stuff::<_, U>(ufa)), ffa)) + } +} diff --git a/src/func/classes/future.rs b/src/func/classes/future.rs index 0d127c1..907ab6d 100644 --- a/src/func/classes/future.rs +++ b/src/func/classes/future.rs @@ -28,6 +28,12 @@ impl Functor for FutureClass { } } +impl Pure for FutureClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + Box::pin(async { a }) + } +} + impl ApplicativeSeq for FutureClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -63,10 +69,6 @@ impl ApplicativeTuple for FutureClass { } impl Applicative for FutureClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - Box::pin(async { a }) - } - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { Box::pin(async { join!(fa, fb).1 }) } diff --git a/src/func/classes/lazy.rs b/src/func/classes/lazy.rs index 123b4f5..b0dde7e 100644 --- a/src/func/classes/lazy.rs +++ b/src/func/classes/lazy.rs @@ -31,6 +31,12 @@ impl Functor for LazyClass { } } +impl Pure for LazyClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + Box::new(|| a) + } +} + impl ApplicativeSeq for LazyClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -60,10 +66,6 @@ impl ApplicativeTuple for LazyClass { } impl Applicative for LazyClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - Box::new(|| a) - } - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { drop(fa); fb diff --git a/src/func/classes/option.rs b/src/func/classes/option.rs index bdd2732..a52d148 100644 --- a/src/func/classes/option.rs +++ b/src/func/classes/option.rs @@ -25,6 +25,12 @@ impl Functor for OptionClass { } } +impl Pure for OptionClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + Some(a) + } +} + impl ApplicativeSeq for OptionClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -54,10 +60,6 @@ impl ApplicativeTuple for OptionClass { } impl Applicative for OptionClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - Some(a) - } - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { fa?; fb diff --git a/src/func/classes/result.rs b/src/func/classes/result.rs index bc6367c..14e1a77 100644 --- a/src/func/classes/result.rs +++ b/src/func/classes/result.rs @@ -25,6 +25,12 @@ impl Functor for ResultClass { } } +impl Pure for ResultClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + Ok(a) + } +} + impl ApplicativeSeq for ResultClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -54,10 +60,6 @@ impl ApplicativeTuple for ResultClass { } impl Applicative for ResultClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - Ok(a) - } - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { fa?; fb diff --git a/src/func/classes/solo.rs b/src/func/classes/solo.rs index 348721b..188a787 100644 --- a/src/func/classes/solo.rs +++ b/src/func/classes/solo.rs @@ -25,6 +25,12 @@ impl Functor for SoloClass { } } +impl Pure for SoloClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + a + } +} + impl ApplicativeSeq for SoloClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -54,10 +60,6 @@ impl ApplicativeTuple for SoloClass { } impl Applicative for SoloClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - a - } - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { drop(fa); fb diff --git a/src/func/classes/stackless.rs b/src/func/classes/stackless.rs index 5575506..1e5b5f8 100644 --- a/src/func/classes/stackless.rs +++ b/src/func/classes/stackless.rs @@ -147,6 +147,12 @@ impl Functor for StacklessClass { } } +impl Pure for StacklessClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + Stackless::from(a) + } +} + impl ApplicativeSeq for StacklessClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -182,10 +188,6 @@ impl ApplicativeTuple for StacklessClass { } impl Applicative for StacklessClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - Stackless::from(a) - } - 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, diff --git a/src/std/tracing.rs b/src/std/tracing.rs index 771caf2..f021cab 100644 --- a/src/std/tracing.rs +++ b/src/std/tracing.rs @@ -96,6 +96,12 @@ impl Functor for TracedClass { } } +impl Pure for TracedClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + a.with_trace(TraceBox::pure()) + } +} + impl ApplicativeSeq for TracedClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -131,10 +137,6 @@ impl ApplicativeTuple for TracedClass { } impl Applicative for TracedClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - a.with_trace(TraceBox::pure()) - } - 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, diff --git a/src/testing/counted.rs b/src/testing/counted.rs index b3e55c1..e4ab7ba 100644 --- a/src/testing/counted.rs +++ b/src/testing/counted.rs @@ -76,6 +76,12 @@ impl Functor for CountedClass { } } +impl Pure for CountedClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + a.with_count(0) + } +} + impl ApplicativeSeq for CountedClass { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -111,10 +117,6 @@ impl ApplicativeTuple for CountedClass { } impl Applicative for CountedClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - a.with_count(0) - } - 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,