RustでApplicative書いてみる

[Functors, Applicatives, And Monads In Pictures](https://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#applicatives)のApplicativeを、Rustで書いてみることにします。

[RustでFunctor書いてみる](https://qiita.com/emo/items/1899767d5e6353fa7c1d)の続きから書きたかったのですが、関数合成とか正直何を言っているのかサッパリ分からなかったので、Applicativeまですっ飛ばすことにします。

前回同様この記事の内容は正しくないかもしれません。どうかご了承くださいますようお願い致します。

##参考資料
[Functors, Applicatives, And Monads In Pictures](https://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)
[箱で考えるFunctor、ApplicativeそしてMonad](https://qiita.com/suin/items/0255f0637921dcdfe83b)
[Monads and GATs in nightly Rust](https://www.fpcomplete.com/blog/monads-gats-nightly-rust/)
[RustのHigher-Kinded type Trait](https://keens.github.io/blog/2016/02/28/rustnohigherkinded_type_trait/)

##Applicative

```Haskell:Haskell
Just (+3) <*> Just 2 == Just 5
```

箱に入った値に、箱に入った関数を適応して、その結果を箱に入れて返すみたいな感じ

Just(2) -> Just(+3) -> Just(5)

```Haskell:Haskell
> (*) <$> Just 5 <*> Just 3
Just 15
```

「(*) <$> Just 5」は「Just(*5)」と同じことなのかな？

```Haskell:Haskell
> liftA2 (*) (Just 5) (Just 3)
Just 15
```

Applicativeだと二つの引数を取る関数を使える感じ？

よくわからないけど、とりあえず書いてみる

```Rust:Rust
#![feature(generic_associated_types)]
#![feature(try_trait)]

trait Functor {
    type Unwrapped;
    type Wrapped<B>: Functor;

    fn fmap<F, B>(self, f: F) -> Self::Wrapped<B>
    where
        F: FnOnce(Self::Unwrapped) -> B;
}

trait Pointed: Functor {
    fn wrap<T>(t: T) -> Self::Wrapped<T>;
}

trait Applicative: Pointed {
    fn lift_a2<F, B, C>(self, b: Self::Wrapped<B>, f: F) -> Self::Wrapped<C>
    where
        F: FnOnce(Self::Unwrapped, B) -> C;
}

//  Maybe
#[derive(Debug, PartialEq)]
enum Maybe<A> {
    Just(A),
    Nothing,
}

// ?部分がコンパイル通らなかったので、Optionを参考に持ってきた
impl<A> Maybe<A> {
    pub fn ok_or<E>(self, err: E) -> Result<A, E> {
        match self {
            Maybe::Just(v) => Ok(v),
            Maybe::Nothing => Err(err),
        }
    }
}

pub struct NoneError;

impl<A> std::ops::Try for Maybe<A> {
    type Ok = A;
    type Error = NoneError;

    #[inline]
    fn into_result(self) -> Result<A, NoneError> {
        self.ok_or(NoneError)
    }

    #[inline]
    fn from_ok(v: A) -> Self {
        Maybe::Just(v)
    }

    #[inline]
    fn from_error(_: NoneError) -> Self {
        Maybe::Nothing
    }
}

// 前回と同じ
impl<A> Functor for Maybe<A> {
    type Unwrapped = A;
    type Wrapped<B> = Maybe<B>;

    fn fmap<F: FnOnce(A) -> B, B>(self, f: F) -> Maybe<B> {
        match self {
            Maybe::Just(x) => Maybe::Just(f(x)),
            Maybe::Nothing => Maybe::Nothing,
        }
    }
}

// ここから Applicative
impl<A> Pointed for Maybe<A> {
    fn wrap<T>(t: T) -> Maybe<T> {
        Maybe::Just(t)
    }
}

impl<A> Applicative for Maybe<A> {
    fn lift_a2<F, B, C>(self, b: Self::Wrapped<B>, f: F) -> Self::Wrapped<C>
    where
        F: FnOnce(Self::Unwrapped, B) -> C,
    {
        let a = self?;
        let b = b?;
        Maybe::Just(f(a, b))
    }
}
```

テストしてみる

```Rust:#[test]
// Just (+3) <*> Just 2 == Just 5
assert_eq!(
    Maybe::Just(|v| 3 + v).lift_a2(Maybe::Just(2), |a, b| a(b)),
    Maybe::Just(5)
);

// Just (*5) <*> Just 3 == Just 15
// (*) <$> Just 5 <*> Just 3 == Just 15
assert_eq!(
    Maybe::Just(|v| 5 * v).lift_a2(Maybe::Just(3), |a, b| a(b)),
    Maybe::Just(15)
);

// liftA2 (*) (Just 5) (Just 3) == Just 15
assert_eq!(
    Maybe::Just(5).lift_a2(Maybe::Just(3), |a, b| a * b),
    Maybe::Just(15)
);
```
ApplicativeはFunctorの別の書き方なのかな？
二つの引数の適応方法も引数で渡せるので色々応用が利くみたいな感じ？

##まとめ

「モナドは奥が深そう」というくらいは理解できたかもしれない、、、