diff --git a/src/func.rs b/src/func.rs index 1e2789b..32fcb40 100644 --- a/src/func.rs +++ b/src/func.rs @@ -146,7 +146,9 @@ pub trait ApplicativeTuple: Functor { /// Split into [`Pure`], [`ApplicativeSeq`], [`ApplicativeLA2`] and [`ApplicativeTuple`] due to Rust limitations. /// /// -pub trait Applicative: Pure + ApplicativeSeq + ApplicativeLA2 + ApplicativeTuple { +pub trait Applicative: + Pure + ApplicativeSeq + ApplicativeLA2 + ApplicativeTuple + ApplicativeSelect +{ /// 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 diff --git a/src/func/applicative_select.rs b/src/func/applicative_select.rs index e3914bb..d5b0a1d 100644 --- a/src/func/applicative_select.rs +++ b/src/func/applicative_select.rs @@ -12,5 +12,8 @@ pub trait ApplicativeSelect: Functor { fb: Self::F<'a, B>, ) -> Self::F<'a, C> where - Self: 'a; + Self: 'a, + { + Self::fmap(|a| f(Selected::A(a, fb)), fa) + } } diff --git a/src/func/classes/composition.rs b/src/func/classes/composition.rs index 0e23c3f..0d9db99 100644 --- a/src/func/classes/composition.rs +++ b/src/func/classes/composition.rs @@ -72,6 +72,26 @@ impl ApplicativeTuple for CompositionC } } +impl ApplicativeSelect for CompositionClass { + fn select<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(Selected<'a, A, B, Self>) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + U::select( + |selected| match selected { + Selected::A(ua, fb) => V::fmap(|a| f(Selected::A(a, fb)), ua), + Selected::B(fa, ub) => V::fmap(|b| f(Selected::B(fa, b)), ub), + }, + fa, + fb, + ) + } +} + 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 diff --git a/src/func/classes/effect.rs b/src/func/classes/effect.rs index c23f8a6..2a3c0bc 100644 --- a/src/func/classes/effect.rs +++ b/src/func/classes/effect.rs @@ -110,6 +110,8 @@ impl ApplicativeTuple for EffectClass { } } +impl ApplicativeSelect for EffectClass {} + impl Applicative for EffectClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> where diff --git a/src/func/classes/future.rs b/src/func/classes/future.rs index c545e3b..036de27 100644 --- a/src/func/classes/future.rs +++ b/src/func/classes/future.rs @@ -5,7 +5,10 @@ use std::{future::Future, pin::Pin}; -use futures::{future::Shared, join, FutureExt}; +use futures::{ + future::{select, Either, Shared}, + join, FutureExt, +}; use crate::func::*; @@ -69,6 +72,24 @@ impl ApplicativeTuple for FutureClass { } } +impl ApplicativeSelect for FutureClass { + fn select<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(Selected<'a, A, B, Self>) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + Box::pin(async { + match select(fa, fb).await { + Either::Left((a, fb)) => f(Selected::A(a, fb)), + Either::Right((b, fa)) => f(Selected::B(fa, b)), + } + }) + } +} + impl Applicative for FutureClass { 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 94d9f06..c2ec04d 100644 --- a/src/func/classes/lazy.rs +++ b/src/func/classes/lazy.rs @@ -68,6 +68,8 @@ impl ApplicativeTuple for LazyClass { } } +impl ApplicativeSelect for LazyClass {} + impl Applicative for LazyClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { drop(fa); diff --git a/src/func/classes/option.rs b/src/func/classes/option.rs index 758da1d..295cd31 100644 --- a/src/func/classes/option.rs +++ b/src/func/classes/option.rs @@ -72,6 +72,8 @@ impl ApplicativeTuple for OptionClass { } } +impl ApplicativeSelect for OptionClass {} + impl Applicative for OptionClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { fa?; diff --git a/src/func/classes/overload.rs b/src/func/classes/overload.rs index 497c38a..886a1cd 100644 --- a/src/func/classes/overload.rs +++ b/src/func/classes/overload.rs @@ -84,6 +84,8 @@ impl ApplicativeTuple for OverloadCla } } +impl ApplicativeSelect for OverloadClass {} + impl Applicative for OverloadClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> where diff --git a/src/func/classes/result.rs b/src/func/classes/result.rs index 254ef1a..54d377d 100644 --- a/src/func/classes/result.rs +++ b/src/func/classes/result.rs @@ -84,6 +84,8 @@ impl ApplicativeTuple for ResultClass { } } +impl ApplicativeSelect for ResultClass {} + impl Applicative for ResultClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> where diff --git a/src/func/classes/solo.rs b/src/func/classes/solo.rs index b631c2a..4ba905a 100644 --- a/src/func/classes/solo.rs +++ b/src/func/classes/solo.rs @@ -60,6 +60,8 @@ impl ApplicativeTuple for SoloClass { } } +impl ApplicativeSelect for SoloClass {} + impl Applicative for SoloClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { drop(fa); diff --git a/src/func/classes/stackless.rs b/src/func/classes/stackless.rs index a0e45c5..5ef61ce 100644 --- a/src/func/classes/stackless.rs +++ b/src/func/classes/stackless.rs @@ -187,6 +187,8 @@ impl ApplicativeTuple for StacklessClass { } } +impl ApplicativeSelect for StacklessClass {} + impl Applicative for StacklessClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> where diff --git a/src/func/classes/tryfuture.rs b/src/func/classes/tryfuture.rs index fd83aeb..342132f 100644 --- a/src/func/classes/tryfuture.rs +++ b/src/func/classes/tryfuture.rs @@ -1,6 +1,9 @@ use std::{future::Future, pin::Pin}; -use futures::{future::Shared, try_join, FutureExt}; +use futures::{ + future::{try_select, Either, Shared}, + try_join, FutureExt, +}; use crate::func::*; @@ -79,6 +82,26 @@ impl ApplicativeTuple for TryFutureClass { } } +impl ApplicativeSelect for TryFutureClass { + fn select<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(Selected<'a, A, B, Self>) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + Box::pin(async { + match try_select(fa, fb).await { + Ok(Either::Left((a, fb))) => Ok(f(Selected::A(a, fb))), + Ok(Either::Right((b, fa))) => Ok(f(Selected::B(fa, b))), + Err(Either::Left((e, _))) => Err(e), + Err(Either::Right((e, _))) => Err(e), + } + }) + } +} + impl Applicative for TryFutureClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> where