From 40937439c7dd665c4c4ea3811e8367cabd59aa4e Mon Sep 17 00:00:00 2001 From: timofey Date: Fri, 26 May 2023 10:03:53 +0000 Subject: [PATCH] `Functor` lift lifetimes --- src/func.rs | 24 ++++++++---------------- src/func/applicative_select.rs | 2 +- src/func/controlflow.rs | 11 ++++------- src/func/derivations.rs | 2 +- src/func/instances/composition.rs | 29 ++++++++++++----------------- src/func/instances/effect.rs | 12 +++--------- src/func/instances/future.rs | 6 +++--- src/func/instances/lazy.rs | 8 ++++---- src/func/instances/option.rs | 14 ++++---------- src/func/instances/overload.rs | 17 ++++------------- src/func/instances/result.rs | 17 ++++------------- src/func/instances/solo.rs | 8 ++++---- src/func/instances/stackless.rs | 12 +++--------- src/func/instances/tryfuture.rs | 12 +++--------- src/func/test_suite.rs | 2 +- src/func/tests.rs | 4 ++-- 16 files changed, 61 insertions(+), 119 deletions(-) diff --git a/src/func.rs b/src/func.rs index f635756..d47356d 100644 --- a/src/func.rs +++ b/src/func.rs @@ -93,39 +93,31 @@ pub type Wrap<'a, A, T> = ::F<'a, A>; /// ``` /// /// -pub trait Functor: WeakFunctor { +pub trait Functor<'a>: 'a + 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; + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B>; /// 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, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { 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, - { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { Self::replace(fa, ()) } } /// Part of [`Applicative`] responsible for Haskell's value lifting, `pure`. -pub trait Pure<'a>: 'a + Functor { +pub trait Pure<'a>: Functor<'a> { /// Equivalent of Haskell's `pure`/`return`. fn pure(a: A) -> Self::F<'a, A>; } /// Part of [`Applicative`] responsible for Haskell's sequential application `<*>`. -pub trait ApplicativeSeq<'a>: 'a + Functor { +pub trait ApplicativeSeq<'a>: Functor<'a> { /// Equivalent of Haskell's `<*>`. fn seq( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, @@ -134,7 +126,7 @@ pub trait ApplicativeSeq<'a>: 'a + Functor { } /// Part of [`Applicative`] responsible for Haskell's result combination `listA2`. -pub trait ApplicativeLA2<'a>: 'a + Functor { +pub trait ApplicativeLA2<'a>: Functor<'a> { /// Equivalent of Haskell's `listA2`. fn la2( f: impl 'a + FnOnce(A, B) -> C, @@ -144,7 +136,7 @@ pub trait ApplicativeLA2<'a>: 'a + Functor { } /// Part of [`Applicative`] responsible for Rust-style result combination, specifically for tuples. -pub trait ApplicativeTuple<'a>: 'a + Functor { +pub trait ApplicativeTuple<'a>: Functor<'a> { /// Similar to Haskell's `listA2` but with [Iterator::collect]-ish semantics. fn tuple(fab: (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)>; } diff --git a/src/func/applicative_select.rs b/src/func/applicative_select.rs index e0dead9..317c26f 100644 --- a/src/func/applicative_select.rs +++ b/src/func/applicative_select.rs @@ -7,7 +7,7 @@ pub enum Selected<'a, A: 'a, B: 'a, T: ?Sized + 'a + WeakFunctor> { pub type SelectedWrapped<'a, A, B, T> = Wrap<'a, Selected<'a, A, B, T>, T>; -pub trait ApplicativeSelect<'a>: 'a + Functor { +pub trait ApplicativeSelect<'a>: Functor<'a> { fn select( fa: Self::F<'a, A>, fb: Self::F<'a, B>, diff --git a/src/func/controlflow.rs b/src/func/controlflow.rs index 3fc9fec..3a718b0 100644 --- a/src/func/controlflow.rs +++ b/src/func/controlflow.rs @@ -10,11 +10,8 @@ impl WeakFunctor for ControlFlowInstance { Self: 'a; } -impl Functor for ControlFlowInstance { - 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, - { +impl<'a, C: 'a> Functor<'a> for ControlFlowInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { match fa { ControlFlow::Continue(c) => ControlFlow::Continue(c), ControlFlow::Break(a) => ControlFlow::Break(f(a)), @@ -32,7 +29,7 @@ pub struct BindableMut(A, F, PhantomData, PhantomData) impl< 'a, - T: 'a + ?Sized + Functor, + T: ?Sized + Functor<'a>, A: 'a, B: 'a, F: 'a + FnMut(A) -> T::F<'a, ControlFlow>, @@ -45,7 +42,7 @@ impl< impl< 'a, - T: 'a + ?Sized + Functor, + T: ?Sized + Functor<'a>, A: 'a, B: 'a, F: 'a + FnMut(A) -> T::F<'a, ControlFlow>, diff --git a/src/func/derivations.rs b/src/func/derivations.rs index 78de10e..7311a4f 100644 --- a/src/func/derivations.rs +++ b/src/func/derivations.rs @@ -3,7 +3,7 @@ use super::*; /// Equivalent of Haskell's `fmap`. `function-function` equivalent of [Functor::fmap]. -pub fn fmap<'a, T: 'a + Functor, A: 'a, B: 'a>( +pub fn fmap<'a, T: Functor<'a>, 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) diff --git a/src/func/instances/composition.rs b/src/func/instances/composition.rs index 80b8f2e..ebce675 100644 --- a/src/func/instances/composition.rs +++ b/src/func/instances/composition.rs @@ -6,25 +6,16 @@ impl WeakFunctor for CompositionInstance { type F<'a, A: 'a> = U::F<'a, V::F<'a, A>> where Self: 'a; } -impl Functor for CompositionInstance { - 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, - { +impl<'a, U: Functor<'a>, V: Functor<'a>> Functor<'a> for CompositionInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { U::fmap(|ua| V::fmap(f, ua), fa) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { U::fmap(|ua| V::replace(ua, b), fa) } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> - where - Self: 'a, - { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { U::fmap(|ua| V::void(ua), fa) } } @@ -66,7 +57,7 @@ impl<'a, U: ApplicativeTuple<'a>, V: ApplicativeTuple<'a>> ApplicativeTuple<'a> } } -impl<'a, U: ApplicativeSelect<'a>, V: 'a + Functor> ApplicativeSelect<'a> +impl<'a, U: ApplicativeSelect<'a>, V: Functor<'a>> ApplicativeSelect<'a> for CompositionInstance { fn select( @@ -142,7 +133,9 @@ impl<'a, E: 'a, U: Monad<'a>, V: Fail<'a, E> + LocalFunctor> Fail<'a, E> } } -impl LocalFunctor for CompositionInstance { +impl Functor<'a>, V: LocalFunctor> LocalFunctor + for CompositionInstance +{ fn unstuff<'a, A: 'a, B: 'a>( state: Self::F<'a, ControlFlow>, ) -> ControlFlow, A> @@ -160,7 +153,9 @@ impl LocalFunctor for CompositionIns } } -impl SharedFunctor for CompositionInstance { +impl Functor<'a>, V: SharedFunctor> SharedFunctor + for CompositionInstance +{ type Shared<'a, A: 'a + Clone> = U::Shared<'a, V::Shared<'a, A>> where Self: 'a; @@ -180,7 +175,7 @@ impl SharedFunctor for Composition } } -impl CovariantFunctor +impl Functor<'a>, V: CovariantFunctor> CovariantFunctor for CompositionInstance { fn variate<'a: 'b, 'b, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'b, A> diff --git a/src/func/instances/effect.rs b/src/func/instances/effect.rs index 5a84f62..a5b7f72 100644 --- a/src/func/instances/effect.rs +++ b/src/func/instances/effect.rs @@ -32,21 +32,15 @@ impl WeakFunctor for EffectInstance { Self: 'a; } -impl Functor for EffectInstance { - 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, - { +impl<'a, E: 'a> Functor<'a> for EffectInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { WithEffect { value: f(fa.value), effect: fa.effect, } } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { drop(fa.value); WithEffect { value: b, diff --git a/src/func/instances/future.rs b/src/func/instances/future.rs index eb33e7f..f46ac02 100644 --- a/src/func/instances/future.rs +++ b/src/func/instances/future.rs @@ -19,12 +19,12 @@ impl WeakFunctor for FutureInstance { type F<'a, A: 'a> = Pin>>; } -impl Functor for FutureInstance { - fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { +impl<'a> Functor<'a> for FutureInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { Box::pin(async { f(fa.await) }) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { Box::pin(async { fa.await; b diff --git a/src/func/instances/lazy.rs b/src/func/instances/lazy.rs index c615597..bc561df 100644 --- a/src/func/instances/lazy.rs +++ b/src/func/instances/lazy.rs @@ -18,17 +18,17 @@ impl WeakFunctor for LazyInstance { type F<'a, A: 'a> = Box A>; } -impl Functor for LazyInstance { - fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { +impl<'a> Functor<'a> for LazyInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { Box::new(|| f(fa())) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { drop(fa); Box::new(|| b) } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { drop(fa); Box::new(|| ()) } diff --git a/src/func/instances/option.rs b/src/func/instances/option.rs index 22c517b..1eb16e8 100644 --- a/src/func/instances/option.rs +++ b/src/func/instances/option.rs @@ -16,23 +16,17 @@ impl WeakFunctor for OptionInstance { type F<'a, A: 'a> = Option; } -impl Functor for OptionInstance { - fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { +impl<'a> Functor<'a> for OptionInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { fa.map(f) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { fa?; Self::pure(b) } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> - where - Self: 'a, - { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { fa?; Self::pure(()) } diff --git a/src/func/instances/overload.rs b/src/func/instances/overload.rs index 22af42a..aad2743 100644 --- a/src/func/instances/overload.rs +++ b/src/func/instances/overload.rs @@ -18,25 +18,16 @@ impl WeakFunctor for OverloadInstance Functor for OverloadInstance { - 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, - { +impl<'a, T: Functor<'a>, O: 'a + DeriveFunctor> Functor<'a> for OverloadInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { T::fmap(f, fa) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { T::replace(fa, b) } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> - where - Self: 'a, - { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { T::void(fa) } } diff --git a/src/func/instances/result.rs b/src/func/instances/result.rs index 1b3764a..e1a19de 100644 --- a/src/func/instances/result.rs +++ b/src/func/instances/result.rs @@ -16,26 +16,17 @@ impl WeakFunctor for ResultInstance { type F<'a, A: 'a> = Result where Self: 'a; } -impl Functor for ResultInstance { - 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, - { +impl<'a, E: 'a> Functor<'a> for ResultInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { fa.map(f) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { fa?; Self::pure(b) } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> - where - Self: 'a, - { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { fa?; Self::pure(()) } diff --git a/src/func/instances/solo.rs b/src/func/instances/solo.rs index c98a764..c7747f2 100644 --- a/src/func/instances/solo.rs +++ b/src/func/instances/solo.rs @@ -11,17 +11,17 @@ impl WeakFunctor for SoloInstance { type F<'a, A: 'a> = A; } -impl Functor for SoloInstance { - fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { +impl<'a> Functor<'a> for SoloInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { f(fa) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { drop(fa); b } - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> { + fn void(fa: Self::F<'a, A>) -> Self::F<'a, ()> { drop(fa); } } diff --git a/src/func/instances/stackless.rs b/src/func/instances/stackless.rs index d40a35d..c1cc2f3 100644 --- a/src/func/instances/stackless.rs +++ b/src/func/instances/stackless.rs @@ -123,18 +123,12 @@ impl WeakFunctor for StacklessInstance { type F<'a, A: 'a> = Stackless<'a, A>; } -impl Functor for StacklessInstance { - 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, - { +impl<'a> Functor<'a> for StacklessInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { fa.map(f) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { Stackless(Box::new(|takesb| { Some(EvalTree::Composite( Box::new(EvalTree::Atom(Box::new(move || fa.call(drop)))), diff --git a/src/func/instances/tryfuture.rs b/src/func/instances/tryfuture.rs index 64218c9..6e10949 100644 --- a/src/func/instances/tryfuture.rs +++ b/src/func/instances/tryfuture.rs @@ -14,18 +14,12 @@ impl WeakFunctor for TryFutureInstance { type F<'a, A: 'a> = Pin>>> where Self: 'a; } -impl Functor for TryFutureInstance { - 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, - { +impl<'a, E: 'a> Functor<'a> for TryFutureInstance { + fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { Box::pin(async { Ok(f(fa.await?)) }) } - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { + fn replace(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { Box::pin(async { fa.await?; Ok(b) diff --git a/src/func/test_suite.rs b/src/func/test_suite.rs index b016277..3386195 100644 --- a/src/func/test_suite.rs +++ b/src/func/test_suite.rs @@ -8,7 +8,7 @@ pub trait FunctorTestSuite: WeakFunctor + Eqr { Self: 'a; } -pub fn functor_follows_laws() -> R { +pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite>() -> R { let mut res = R::default(); T::sample(|pa| { res += fmap_respects_identity::(|| pa(2)); diff --git a/src/func/tests.rs b/src/func/tests.rs index f6c2253..ad20c79 100644 --- a/src/func/tests.rs +++ b/src/func/tests.rs @@ -91,7 +91,7 @@ impl AddAssign for R { } } -pub fn fmap_respects_identity<'a, T: 'a + Functor + Eqr, A: 'a + Debug + PartialEq>( +pub fn fmap_respects_identity<'a, T: Functor<'a> + Eqr, A: 'a + Debug + PartialEq>( fa0: impl Fn() -> T::F<'a, A>, ) -> R { T::eqr("identity: fmap id == id", T::fmap(|a| a, fa0()), fa0()) @@ -99,7 +99,7 @@ pub fn fmap_respects_identity<'a, T: 'a + Functor + Eqr, A: 'a + Debug + Partial pub fn fmap_respects_composition< 'a, - T: 'a + Functor + Eqr, + T: Functor<'a> + Eqr, A: 'a, B: 'a, C: 'a + Debug + PartialEq,