impl ApplicativeSelect

This commit is contained in:
AF 2023-05-22 11:07:16 +00:00
parent b9cc2a7eed
commit 7caf80f372
12 changed files with 87 additions and 4 deletions

View File

@ -146,7 +146,9 @@ pub trait ApplicativeTuple: Functor {
/// Split into [`Pure`], [`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: 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

View File

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

View File

@ -72,6 +72,26 @@ impl<U: ApplicativeTuple, V: ApplicativeTuple> ApplicativeTuple for CompositionC
}
}
impl<U: ApplicativeSelect, V: ApplicativeSelect> ApplicativeSelect for CompositionClass<U, V> {
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<U: Applicative, V: Applicative> Applicative for CompositionClass<U, V> {
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where

View File

@ -110,6 +110,8 @@ impl<E: Effect> ApplicativeTuple for EffectClass<E> {
}
}
impl<E: Effect> ApplicativeSelect for EffectClass<E> {}
impl<E: Effect> Applicative for EffectClass<E> {
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where

View File

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

View File

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

View File

@ -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?;

View File

@ -84,6 +84,8 @@ impl<T: ApplicativeTuple, O: DeriveApplicative> ApplicativeTuple for OverloadCla
}
}
impl<T: ApplicativeTuple, O: DeriveApplicative> ApplicativeSelect for OverloadClass<T, O> {}
impl<T: Applicative, O: DeriveApplicative> Applicative for OverloadClass<T, O> {
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where

View File

@ -84,6 +84,8 @@ impl<E> ApplicativeTuple for ResultClass<E> {
}
}
impl<E> ApplicativeSelect for ResultClass<E> {}
impl<E> Applicative for ResultClass<E> {
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where

View File

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

View File

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

View File

@ -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<E> ApplicativeTuple for TryFutureClass<E> {
}
}
impl<E> ApplicativeSelect for TryFutureClass<E> {
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<E> Applicative for TryFutureClass<E> {
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B>
where