1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::*;

pub struct TypeCon;

impl<T> TypeAppParam for Option<T> {
    type Param = T;
}

impl<T> TypeApp<TypeCon, T> for Option<T> {}

impl<T> WithTypeArg<T> for TypeCon {
    type Type = Option<T>;
}

impl Functor for TypeCon {
    fn fmap<TIn, TOut, F>(
        f: F,
        x: &<TypeCon as WithTypeArg<TIn>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        F: Fn(&TIn) -> TOut,
    {
        Option::map(x.as_ref(), f)
    }
}

impl LinearFunctor for TypeCon {
    fn lmap<TIn, TOut, F>(
        f: F,
        x: <TypeCon as WithTypeArg<TIn>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        F: Fn(TIn) -> TOut,
    {
        Option::map(x, f)
    }
}

impl Lift for TypeCon {
    fn lift<T>(x: T) -> <TypeCon as WithTypeArg<T>>::Type {
        From::from(x)
    }
}

impl Applicative for TypeCon {
    fn ap<TIn, TOut, TFunc>(
        f: &<TypeCon as WithTypeArg<TFunc>>::Type,
        x: &<TypeCon as WithTypeArg<TIn>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        TFunc: Fn(&TIn) -> TOut,
    {
        f.as_ref().and_then(|f_val| fmap(f_val, x))
    }

    fn lift2<TIn1, TIn2, TOut, TFunc>(
        f: TFunc,
        x1: &<TypeCon as WithTypeArg<TIn1>>::Type,
        x2: &<TypeCon as WithTypeArg<TIn2>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        TFunc: Fn(&TIn1, &TIn2) -> TOut,
    {
        x1.as_ref()
            .and_then(|x1_val| x2.as_ref().map(|x2_val| f(x1_val, x2_val)))
    }
}

impl LinearApplicative for TypeCon {
    fn lap<TIn, TOut, TFunc>(
        f: <TypeCon as WithTypeArg<TFunc>>::Type,
        x: <TypeCon as WithTypeArg<TIn>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        TFunc: FnOnce(TIn) -> TOut,
    {
        f.and_then(|f_val| x.map(|x_val| f_val(x_val)))
    }

    fn llift2<TIn1, TIn2, TOut, TFunc>(
        f: TFunc,
        x1: <TypeCon as WithTypeArg<TIn1>>::Type,
        x2: <TypeCon as WithTypeArg<TIn2>>::Type,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        TFunc: FnOnce(TIn1, TIn2) -> TOut,
    {
        x1.and_then(|x1val| x2.map(|x2val| f(x1val, x2val)))
    }
}

impl Monad for TypeCon {
    fn bind<TIn, TOut, F>(
        x: &<TypeCon as WithTypeArg<TIn>>::Type,
        f: F,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        F: Fn(&TIn) -> <TypeCon as WithTypeArg<TOut>>::Type,
    {
        x.as_ref().and_then(f)
    }
}

impl LinearMonad for TypeCon {
    fn lbind<TIn, TOut, F>(
        x: <TypeCon as WithTypeArg<TIn>>::Type,
        f: F,
    ) -> <TypeCon as WithTypeArg<TOut>>::Type
    where
        F: FnOnce(TIn) -> <TypeCon as WithTypeArg<TOut>>::Type,
    {
        x.and_then(f)
    }
}