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
use crate::plug::{Plug, Plug2, Unplug, Unplug2};

pub trait Functor: Unplug + Plug<<Self as Unplug>::A> {
    fn fmap<B, F>(self, f: F) -> <Self as Plug<B>>::Out
    where
        Self: Plug<B>,
        F: FnOnce(<Self as Unplug>::A) -> B;
}

pub trait Apply: Functor {
    fn ap<B, F>(self, f: <Self as Plug<F>>::Out) -> <Self as Plug<B>>::Out
    where
        Self: Plug<B> + Plug<F>,
        F: FnOnce(<Self as Unplug>::A) -> B;
}

pub trait Applicative: Apply {
    fn pure(value: <Self as Unplug>::A) -> Self;
}

pub trait Monad: Applicative {
    fn bind<B, F>(self, f: F) -> <Self as Plug<B>>::Out
    where
        Self: Plug<B>,
        F: FnOnce(<Self as Unplug>::A) -> <Self as Plug<B>>::Out;
}

pub trait Semigroup {
    fn combine(self, other: Self) -> Self;
}

pub trait Monoid: Semigroup {
    fn mempty() -> Self;
}

pub trait Foldable: Unplug + Plug<<Self as Unplug>::A> {
    fn fold_left<B, F>(self, init: B, f: F) -> B
    where
        F: FnOnce(B, <Self as Unplug>::A) -> B;
}

pub trait Traverse: Functor + Foldable {
    fn traverse<F, M, B>(self, f: F) -> <M as Plug<<Self as Plug<B>>::Out>>::Out
    where
        Self: Plug<B>,
        M: Plug<<Self as Plug<B>>::Out> + Plug<B> + Applicative,
        F: FnOnce(<Self as Unplug>::A) -> <M as Plug<B>>::Out;
}

pub trait Show {
    fn show(a: Self) -> String;
}

pub trait Contravariant: Unplug + Plug<<Self as Unplug>::A> {
    fn contramap<B, F>(self, f: F) -> <Self as Plug<B>>::Out
    where
        Self: Plug<B>,
        F: FnOnce(B) -> <Self as Unplug>::A;
}

pub trait Alternative: Applicative {
    fn empty() -> Self;
    fn combine(self, other: Self) -> Self;
}

pub trait Bifunctor: Unplug2 + Plug2<<Self as Unplug2>::A, <Self as Unplug2>::B> {
    fn bimap<C, D, F, G>(self, f: F, g: G) -> <Self as Plug2<C, D>>::Out
    where
        Self: Plug2<C, D>,
        F: FnOnce(<Self as Unplug2>::A) -> C,
        G: FnOnce(<Self as Unplug2>::B) -> D;
}