functional 0.0.7

Functional traits
use hkt::*;
use super::applicative::Applicative;

/// Monad trait.
pub trait Monad: Applicative {

    /// Bind monadic value to the monadic action
    /// `m.bind(f)` is equvalent of `m.fmap(f).join()`
    fn bind<U, F>(self, f: F) -> rebind1!(Self, U)
        where Self::Unit: Rebind1<U>,
              generic1!(Self): Sized,
              F: Fn(generic1!(Self)) -> rebind1!(Self, U);

    /// Join two level of monad into one `M<M<T>> => M<T>`
    /// `m.join()` is equivalent of `m.bind(|x|x)`
    fn join<U>(self) -> rebind1!(Self, U)
        where Self: Sized,
              Self: Generic1,
              Self::Unit: Rebind1<U>,
              generic1!(Self): Same<Type=rebind1!(Self, U)> + Sized,
              generic1!(Self): Generic1<Unit=Self::Unit>;
}


impl<T> Monad for Option<T> {
    fn bind<U, F>(self, f: F) -> rebind1!(Self, U)
        where F: Fn(T) -> Option<U>
    {
        match self {
            Some(x) => f(x),
            None => None
        }
    }

    fn join<U>(self) -> rebind1!(Self, U)
        where generic1!(Self): Same<Type=rebind1!(Self, U)>
    {        
        match self {
            Some(x) => x.same_cast(),
            None => None
        }
    }
}


impl<T, E> Monad for Result<T, E> {    
    fn bind<U, F>(self, f: F) -> rebind1!(Self, U)
        where F: Fn(T) -> Result<U, E>       
    {
        match self {
            Ok(x) => f(x),
            Err(err) => Err(err)
        }
    }

    fn join<U>(self) -> rebind1!(Self, U)
        where generic1!(Self): Same<Type=rebind1!(Self, U)>
    {        
        match self {
            Ok(x) => x.same_cast(),
            Err(err) => Err(err)
        }
    }
}




impl<T> Monad for Vec<T> where T: Clone {    
    fn bind<U, F>(self, f: F) -> rebind1!(Self, U)
        where F: Fn(T) -> Vec<U>
    {
        self.into_iter().flat_map(|x| f(x)).collect()
    }

    fn join<U>(self) -> rebind1!(Self, U)
        where generic1!(Self): Same<Type=rebind1!(Self, U)>
    {
        self.into_iter().flat_map(|x| x.same_cast()).collect()
    }
}