Functor lift lifetimes

This commit is contained in:
AF 2023-05-26 10:03:53 +00:00
parent 044ffbcda0
commit 40937439c7
16 changed files with 61 additions and 119 deletions

View File

@ -93,39 +93,31 @@ pub type Wrap<'a, A, T> = <T as WeakFunctor>::F<'a, A>;
/// ```
///
/// <https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Functor.html>
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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(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>(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<A: 'a, B: 'a>(
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<A: 'a, B: 'a, C: 'a>(
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<A: 'a, B: 'a>(fab: (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)>;
}

View File

@ -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<A: 'a, B: 'a>(
fa: Self::F<'a, A>,
fb: Self::F<'a, B>,

View File

@ -10,11 +10,8 @@ impl<C> WeakFunctor for ControlFlowInstance<C> {
Self: 'a;
}
impl<C> Functor for ControlFlowInstance<C> {
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<C> {
fn fmap<A: 'a, B: 'a>(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<T: ?Sized, A, B, F>(A, F, PhantomData<B>, PhantomData<T>)
impl<
'a,
T: 'a + ?Sized + Functor,
T: ?Sized + Functor<'a>,
A: 'a,
B: 'a,
F: 'a + FnMut(A) -> T::F<'a, ControlFlow<B, A>>,
@ -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<B, A>>,

View File

@ -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)

View File

@ -6,25 +6,16 @@ impl<U: WeakFunctor, V: WeakFunctor> WeakFunctor for CompositionInstance<U, V> {
type F<'a, A: 'a> = U::F<'a, V::F<'a, A>> where Self: 'a;
}
impl<U: Functor, V: Functor> Functor for CompositionInstance<U, V> {
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<U, V> {
fn fmap<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(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<U, V>
{
fn select<A: 'a, B: 'a>(
@ -142,7 +133,9 @@ impl<'a, E: 'a, U: Monad<'a>, V: Fail<'a, E> + LocalFunctor> Fail<'a, E>
}
}
impl<U: LocalFunctor + Functor, V: LocalFunctor> LocalFunctor for CompositionInstance<U, V> {
impl<U: LocalFunctor + for<'a> Functor<'a>, V: LocalFunctor> LocalFunctor
for CompositionInstance<U, V>
{
fn unstuff<'a, A: 'a, B: 'a>(
state: Self::F<'a, ControlFlow<B, A>>,
) -> ControlFlow<Self::F<'a, B>, A>
@ -160,7 +153,9 @@ impl<U: LocalFunctor + Functor, V: LocalFunctor> LocalFunctor for CompositionIns
}
}
impl<U: SharedFunctor + Functor, V: SharedFunctor> SharedFunctor for CompositionInstance<U, V> {
impl<U: SharedFunctor + for<'a> Functor<'a>, V: SharedFunctor> SharedFunctor
for CompositionInstance<U, V>
{
type Shared<'a, A: 'a + Clone> = U::Shared<'a, V::Shared<'a, A>>
where
Self: 'a;
@ -180,7 +175,7 @@ impl<U: SharedFunctor + Functor, V: SharedFunctor> SharedFunctor for Composition
}
}
impl<U: CovariantFunctor + Functor, V: CovariantFunctor> CovariantFunctor
impl<U: CovariantFunctor + for<'a> Functor<'a>, V: CovariantFunctor> CovariantFunctor
for CompositionInstance<U, V>
{
fn variate<'a: 'b, 'b, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'b, A>

View File

@ -32,21 +32,15 @@ impl<E> WeakFunctor for EffectInstance<E> {
Self: 'a;
}
impl<E> Functor for EffectInstance<E> {
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<E> {
fn fmap<A: 'a, B: 'a>(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<A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> {
drop(fa.value);
WithEffect {
value: b,

View File

@ -19,12 +19,12 @@ impl WeakFunctor for FutureInstance {
type F<'a, A: 'a> = Pin<Box<dyn 'a + Future<Output = A>>>;
}
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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> {
Box::pin(async {
fa.await;
b

View File

@ -18,17 +18,17 @@ impl WeakFunctor for LazyInstance {
type F<'a, A: 'a> = Box<dyn 'a + FnOnce() -> 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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
drop(fa);
Box::new(|| ())
}

View File

@ -16,23 +16,17 @@ impl WeakFunctor for OptionInstance {
type F<'a, A: 'a> = Option<A>;
}
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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
fa?;
Self::pure(())
}

View File

@ -18,25 +18,16 @@ impl<T: WeakFunctor, O: DeriveWeakFunctor> WeakFunctor for OverloadInstance<T, O
Self: 'a;
}
impl<T: Functor, O: DeriveFunctor> Functor for OverloadInstance<T, O> {
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<T, O> {
fn fmap<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
T::void(fa)
}
}

View File

@ -16,26 +16,17 @@ impl<E> WeakFunctor for ResultInstance<E> {
type F<'a, A: 'a> = Result<A, E> where Self: 'a;
}
impl<E> Functor for ResultInstance<E> {
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<E> {
fn fmap<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
fa?;
Self::pure(())
}

View File

@ -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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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<A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
drop(fa);
}
}

View File

@ -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<A: 'a, B: 'a>(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<A: 'a, B: 'a>(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)))),

View File

@ -14,18 +14,12 @@ impl<E> WeakFunctor for TryFutureInstance<E> {
type F<'a, A: 'a> = Pin<Box<dyn 'a + Future<Output = Result<A, E>>>> where Self: 'a;
}
impl<E> Functor for TryFutureInstance<E> {
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<E> {
fn fmap<A: 'a, B: 'a>(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<A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> {
Box::pin(async {
fa.await?;
Ok(b)

View File

@ -8,7 +8,7 @@ pub trait FunctorTestSuite: WeakFunctor + Eqr {
Self: 'a;
}
pub fn functor_follows_laws<T: Functor + FunctorTestSuite>() -> R {
pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite>() -> R {
let mut res = R::default();
T::sample(|pa| {
res += fmap_respects_identity::<T, _>(|| pa(2));

View File

@ -91,7 +91,7 @@ impl AddAssign<R> 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,