use crate::Functor;
pub trait Apply<'a>: Functor<'a> {
fn ap<F, B: 'a>(self, f: Self::Wrapped<F>) -> Self::Wrapped<B>
where
F: FnOnce(Self::Unwrapped) -> B + 'a;
fn lift_a2<F, B: 'a, C: 'a>(self, b: Self::Wrapped<B>, f: F) -> Self::Wrapped<C>
where
F: FnOnce(Self::Unwrapped, B) -> C + 'a;
}
impl<'a, A> Apply<'a> for Option<A> {
fn ap<F, B: 'a>(self, f: Self::Wrapped<F>) -> Self::Wrapped<B>
where
F: FnOnce(Self::Unwrapped) -> B + 'a,
{
match self {
Some(x) => match f {
Some(z) => Some(z(x)),
None => None,
},
None => None,
}
}
fn lift_a2<F, B: 'a, C: 'a>(self, b: Self::Wrapped<B>, f: F) -> Self::Wrapped<C>
where
F: FnOnce(Self::Unwrapped, B) -> C,
{
match self {
Some(x) => match b {
Some(y) => Some(f(x, y)),
None => None,
},
None => None,
}
}
}
impl<'a, A, E> Apply<'a> for Result<A, E> {
fn ap<F, B: 'a>(self, f: Self::Wrapped<F>) -> Self::Wrapped<B>
where
F: FnOnce(Self::Unwrapped) -> B + 'a,
{
match self {
Result::Ok(x) => match f {
Result::Ok(z) => Result::Ok(z(x)),
Result::Err(e) => Result::Err(e),
},
Result::Err(e) => Result::Err(e),
}
}
fn lift_a2<F, B: 'a, C: 'a>(self, b: Self::Wrapped<B>, f: F) -> Self::Wrapped<C>
where
F: FnOnce(Self::Unwrapped, B) -> C,
{
match self {
Result::Ok(x) => match b {
Result::Ok(y) => Result::Ok(f(x, y)),
Result::Err(e) => Result::Err(e),
},
Result::Err(e) => Result::Err(e),
}
}
}
#[cfg(test)]
mod test {
use crate::Apply;
#[test]
fn option_ap() {
let a = Option::Some(31337);
let b = a.ap(Some(|x| format!("{}", x)));
assert_eq!(b, Option::Some("31337".to_string()));
}
#[test]
fn option_lifta2() {
let a = Option::Some(42);
let b = Option::Some(2);
let res = a.lift_a2(b, |u1, u2| u1 + u2);
assert_eq!(res, Option::Some(44));
}
#[test]
fn result_ap() {
let a: Result<i32, ()> = Result::Ok(31337);
let b = a.ap(Result::Ok(|x| format!("{}", x)));
assert_eq!(b, Result::Ok("31337".to_string()));
}
}