lubeck 0.0.0-prealpha.5-abandoned

Functional programming framework written in cutting edge rust
Documentation
use crate::common::reader::Reader;
use crate::prelude::{Applicative, Functor, GenType, Monad};

// Read a Config an get an Option

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
                // Option<A> -> Option<Reader<R, Option<B>>>
                .map(f)
                // Option<Reader<R, Option<B>>> -> Option<B>
                .and_then(|reader_opt_b| {
                    // Reader<R, Option<B>> -> Option<B>
                    reader_opt_b.run_reader_option.run(r)
                })
        });
        Self::Type::<B> {
            run_reader_option: reader_opt_b,
        }
    }
}