use crate::prelude::{Applicative, Functor, GenType, Monad};
use std::marker::PhantomData;
pub struct OptionT<'a, M, A>
where
M: GenType<Type<Option<A>> = M> + Monad<'a, Option<A>>,
A: 'a,
{
pub run_option_t: M::Type<Option<A>>,
pub _pd: PhantomData<&'a ()>,
}
impl<'a, M, A> GenType for OptionT<'a, M, A>
where
M: GenType<Type<Option<A>> = M> + Monad<'a, Option<A>>,
A: 'a,
{
type Type<T> = M::Type<Option<T>>;
}
impl<'a, M, A> Functor<'a, A> for OptionT<'a, M, A>
where
M: GenType<Type<Option<A>> = M> + Monad<'a, Option<A>>,
A: 'a,
{
fn fmap<F, B: 'a>(self, f: F) -> Self::Type<B>
where
F: Fn(A) -> B + 'a,
{
self.run_option_t
.fmap(move |opt_a: Option<A>| opt_a.fmap(|a| f(a)))
}
}
impl<'a, M, A> Applicative<'a, A> for OptionT<'a, M, A>
where
M: GenType<Type<Option<A>> = M>
+ Applicative<'a, Option<A>, PureT<Option<A>> = Option<A>>
+ Monad<'a, Option<A>>,
A: 'a,
{
type PureT<T> = T where T: 'a ;
fn pure(a: Self::PureT<A>) -> Self::Type<Self::PureT<A>> {
M::pure(Some(a))
}
fn app<F, B>(self, f: Self::Type<F>) -> Self::Type<B>
where
F: Fn(A) -> B + 'a,
B: 'a,
{
todo!(
"Probably something like
// self = M<Option<A>>
self.app(
// f before fmap = M<Option<Fn(A) -> B>>
// f after fmap = M<Fn(Option<A>) -> Option<B>> => can use app of M
f
.fmap(
// f_in_opt = Option<Fn(A) -> B>
|f_in_opt|
// Fn(Option<A>) -> Option<B>
move |opt_a: Option<A>| opt_a.app(f_in_opt))
)
"
)
}
}