use crate::common::reader::Reader;
use crate::prelude::{Applicative, Functor, GenType, Monad};
pub struct ReaderOptionT<'a, R, A>
where
R: Clone,
{
run_reader_option: Reader<'a, R, Option<A>>,
}
impl<'a, R, A> ReaderOptionT<'a, R, A>
where
R: Clone,
{
pub fn new<F>(f: F) -> Self
where
F: FnOnce(R) -> Option<A> + 'a,
{
Self {
run_reader_option: Reader::new(f),
}
}
pub fn run(self, r: R) -> Option<A> {
self.run_reader_option.run(r)
}
}
impl<'a, R, A> GenType for ReaderOptionT<'a, R, A>
where
R: Clone,
{
type Type<T> = ReaderOptionT<'a, R, T>;
}
impl<'a, R, A> Functor<'a, A> for ReaderOptionT<'a, R, A>
where
R: Clone + 'a,
A: 'a,
{
fn fmap<F, B: 'a>(self, f: F) -> Self::Type<B>
where
F: Fn(A) -> B + 'a,
{
let reader_opt_b = self
.run_reader_option
.fmap(move |opt_a: Option<A>| opt_a.fmap(|a| f(a)));
Self::Type::<B> {
run_reader_option: reader_opt_b,
}
}
}
impl<'a, R, A> Applicative<'a, A> for ReaderOptionT<'a, R, A>
where
R: Clone + 'a,
A: 'a,
{
type PureT<T: 'a> = T;
fn pure(a: Self::PureT<A>) -> Self::Type<Self::PureT<A>> {
let opt_a = Option::<A>::pure(a);
let reader_opt_a = Reader::<'a, R, Option<A>>::pure(opt_a);
Self::Type::<Self::PureT<A>> {
run_reader_option: reader_opt_a,
}
}
fn app<F, B: 'a>(self, f: Self::Type<F>) -> Self::Type<B>
where
F: Fn(A) -> B + 'a,
{
let reader_opt_b = Reader::new(move |r: R| {
let opt_a = self.run_reader_option.run(r.clone());
let opt_f = f.run_reader_option.run(r);
opt_a.app(opt_f)
});
Self::Type::<B> {
run_reader_option: reader_opt_b,
}
}
}
impl<'a, R, A> Monad<'a, A> for ReaderOptionT<'a, R, A>
where
R: Clone + 'a,
A: 'a,
{
fn bind<F, B: 'a>(self, f: F) -> Self::Type<B>
where
F: Fn(A) -> Self::Type<B> + 'a,
{
let reader_opt_b = Reader::new(move |r: R| {
let opt_a = self.run_reader_option.run(r.clone());
opt_a
.map(f)
.and_then(|reader_opt_b| {
reader_opt_b.run_reader_option.run(r)
})
});
Self::Type::<B> {
run_reader_option: reader_opt_b,
}
}
}