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
use crate::{Bind, Pure};
use higher::{Lift, Lift3};

/// `Ap` provides an implementation for `Apply::apply` using only `Bind` and
/// `Pure`.
pub trait Ap<A, F, B>: Lift3<A, F, B> + Bind<A, B>
where
    A: Clone,
    <Self as Lift3<A, F, B>>::Target2: Bind<F, B> + Clone,
    <<Self as Lift3<A, F, B>>::Target2 as Lift<F, B>>::Target1: Pure<B>,
    F: Fn(A) -> B,
{
    fn ap(self, f: <Self as Lift3<A, F, B>>::Target2) -> <Self as Lift<A, B>>::Target1;
}

impl<M, A, F, B> Ap<A, F, B> for M
where
    M: Lift3<A, F, B> + Bind<A, B>,
    A: Clone,
    <M as Lift3<A, F, B>>::Target2: Bind<F, B> + Clone,
    <<M as Lift3<A, F, B>>::Target2 as Lift<F, B>>::Target1: Pure<B>,
    F: Fn(A) -> B,
{
    fn ap(self, f: <Self as Lift3<A, F, B>>::Target2) -> <Self as Lift<A, B>>::Target1 {
        self.bind(|v: A| {
            let m: <<Self as Lift3<A, F, B>>::Target2 as Lift<F, B>>::Target1 =
                f.clone().bind(|fun: F| Pure::pure(fun(v.clone())));
            Self::cast(m)
        })
    }
}