Applicative

This commit is contained in:
AF 2024-05-13 21:49:57 +03:00
parent c4d4448745
commit 887807c740
Signed by: alisa
SSH Key Fingerprint: SHA256:vNY4pdIZvO1FYJKHROkdHLtvyopizvZVAEwg9AF6h04

View File

@ -4,7 +4,7 @@ use std::{
task::{Context, Poll},
};
use futures::Future;
use futures::{join, Future};
use pin_project::pin_project;
pub trait Trait {
@ -87,6 +87,11 @@ pub trait TraitFn<In: ?Sized + Trait> {
fn run(self, _: impl Impl<In>) -> impl Impl<Self::Out>;
}
pub trait TraitFn2<In0: ?Sized + Trait, In1: ?Sized + Trait> {
type Out: ?Sized + Trait;
fn run(self, _: impl Impl<In0>, _: impl Impl<In1>) -> impl Impl<Self::Out>;
}
pub trait Functor {
type W<T: ?Sized + Trait>: ?Sized + Trait;
fn pure<A: ?Sized + Trait>(_: impl Impl<A>) -> impl Impl<Self::W<A>>;
@ -96,6 +101,18 @@ pub trait Functor {
) -> impl Impl<Self::W<F::Out>>;
}
pub trait Applicative: Functor {
fn map2<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>>(
_: impl Impl<Self::W<A>>,
_: impl Impl<Self::W<B>>,
_: F,
) -> impl Impl<Self::W<F::Out>>;
}
pub trait Monad: Functor {
fn flatten<A: ?Sized + Trait>(_: impl Impl<Self::W<Self::W<A>>>) -> impl Impl<Self::W<A>>;
}
pub struct Verbatim;
impl Functor for Verbatim {
@ -113,6 +130,22 @@ impl Functor for Verbatim {
}
}
impl Applicative for Verbatim {
fn map2<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>>(
a: impl Impl<Self::W<A>>,
b: impl Impl<Self::W<B>>,
f: F,
) -> impl Impl<Self::W<F::Out>> {
f.run(a, b)
}
}
impl Monad for Verbatim {
fn flatten<A: ?Sized + Trait>(a: impl Impl<Self::W<Self::W<A>>>) -> impl Impl<Self::W<A>> {
a
}
}
pub trait Call<T: ?Sized + Trait> {
type Output: Impl<T>;
fn call(self) -> Self::Output;
@ -143,9 +176,25 @@ impl Functor for Lazy {
}
}
impl Applicative for Lazy {
fn map2<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>>(
a: impl Impl<Self::W<A>>,
b: impl Impl<Self::W<B>>,
f: F,
) -> impl Impl<Self::W<F::Out>> {
|| f.run(a.call(), b.call())
}
}
impl Monad for Lazy {
fn flatten<A: ?Sized + Trait>(a: impl Impl<Self::W<Self::W<A>>>) -> impl Impl<Self::W<A>> {
|| a.call().call()
}
}
pub struct Composition<Uo, Ui>(Uo, Ui);
impl<Uo: Functor, Ui: Functor> Functor for Composition<Ui, Uo> {
impl<Uo: Functor, Ui: Functor> Functor for Composition<Uo, Ui> {
type W<T: ?Sized + Trait> = Uo::W<Ui::W<T>>;
fn pure<A: ?Sized + Trait>(a: impl Impl<A>) -> impl Impl<Self::W<A>> {
@ -156,17 +205,38 @@ impl<Uo: Functor, Ui: Functor> Functor for Composition<Ui, Uo> {
a: impl Impl<Self::W<A>>,
f: F,
) -> impl Impl<Self::W<F::Out>> {
struct Tmp<A: ?Sized, F, Uo, Ui>(F, PhantomData<(Uo, Ui, A)>);
impl<A: ?Sized + Trait, F: TraitFn<A>, Uo: Functor, Ui: Functor> TraitFn<Ui::W<A>>
for Tmp<A, F, Uo, Ui>
{
struct Tmp<A: ?Sized, F, Ui>(F, PhantomData<(Ui, A)>);
impl<A: ?Sized + Trait, F: TraitFn<A>, Ui: Functor> TraitFn<Ui::W<A>> for Tmp<A, F, Ui> {
type Out = Ui::W<F::Out>;
fn run(self, a: impl Impl<Ui::W<A>>) -> impl Impl<Self::Out> {
Ui::map(a, self.0)
}
}
Uo::map(a, Tmp::<A, F, Uo, Ui>(f, PhantomData))
Uo::map(a, Tmp::<A, F, Ui>(f, PhantomData))
}
}
impl<Uo: Applicative, Ui: Applicative> Applicative for Composition<Uo, Ui> {
fn map2<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>>(
a: impl Impl<Self::W<A>>,
b: impl Impl<Self::W<B>>,
f: F,
) -> impl Impl<Self::W<F::Out>> {
struct Tmp<A: ?Sized, B: ?Sized, F, Ui>(
F,
PhantomData<(Ui, PhantomData<A>, PhantomData<B>)>,
);
impl<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>, Ui: Applicative>
TraitFn2<Ui::W<A>, Ui::W<B>> for Tmp<A, B, F, Ui>
{
type Out = Ui::W<F::Out>;
fn run(self, a: impl Impl<Ui::W<A>>, b: impl Impl<Ui::W<B>>) -> impl Impl<Self::Out> {
Ui::map2(a, b, self.0)
}
}
Uo::map2(a, b, Tmp::<A, B, F, Ui>(f, PhantomData))
}
}
@ -264,6 +334,25 @@ impl Functor for Futures {
}
}
impl Applicative for Futures {
fn map2<A: ?Sized + Trait, B: ?Sized + Trait, F: TraitFn2<A, B>>(
a: impl Impl<Self::W<A>>,
b: impl Impl<Self::W<B>>,
f: F,
) -> impl Impl<Self::W<F::Out>> {
async {
let (a, b) = join!(a.into_future_(), b.into_future_());
f.run(a, b)
}
}
}
impl Monad for Futures {
fn flatten<A: ?Sized + Trait>(a: impl Impl<Self::W<Self::W<A>>>) -> impl Impl<Self::W<A>> {
async { a.into_future_().await.into_future_().await }
}
}
#[test]
fn with_futures() {
type U = Futures;
@ -276,7 +365,6 @@ fn with_futures() {
fn doubly_futures() {
type U = Composition<Futures, Futures>;
let x = generic_test::<U>();
let x = futures::executor::block_on(async { x.into_future_().await.into_future_().await })
.into_::<i32>();
let x = futures::executor::block_on(Futures::flatten(x).into_future_()).into_::<i32>();
assert_eq!(x, 10);
}