少し前にRustのnightlyにGATが入ったらしいので、Functors, Applicatives, And Monads In PicturesのFunctorまでを、Rustで書いてみることにしました。

Rustは趣味でコードを書いている程度で、Haskellは一行も書いたことがありません。それに、モナドが何なのかもサッパリ分かりません。なので、この記事の内容は正しくないかもしれません。どうかご了承くださいますようお願い致します。

あと、今回使用したRustのバージョンは、「rustc 1.51.0-nightly (0b644e419 2020-12-26)」になります。

参考資料

Functors, Applicatives, And Monads In Pictures
箱で考えるFunctor、ApplicativeそしてMonad
Monads and GATs in nightly Rust
RustのHigher-Kinded type Trait

Maybe

data Maybe a = Nothing | Just a

Maybe データ型、 Just a と Nothing の状態を表す

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

Functor

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

> fmap (+3) Nothing
Nothing

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

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

とりあえず書いてみる

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

テストしてみる

assert_eq!(Maybe::Just(2).fmap(|v| 3 + v), Maybe::Just(5));
assert_eq!(Maybe::Nothing.fmap(|v: i32| 3 + v), Maybe::Nothing);

これって Option

assert_eq!(Some(2).map(|v| 3 + v), Some(5));
assert_eq!(None.map(|v: i32| 3 + v), None);

Haskell の typeclass は、Rust の trait らしいので trait で書きなおす

class Functor f where
    map :: (a -> b) -> f a -> f b
instance Functor Maybe where
    fmap func (Just val) = Just (func val)
    fmap func Nothing = Nothing
trait Functor<A> {
    fn fmap<B, F: FnOnce(A) -> B>(self, f: F) -> Maybe<B>;
}

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

あれ?書けた気がする?

GAT

気を取り直して本題のGATで書いてみる

#![feature(generic_associated_types)]

を頭に追加して

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

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

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,
        }
    }
}

HKT

実はGAT入る前から書けてた

RustにはHKTないけど、関連型を駆使して書けるらしい

trait HKT<U> {
    type Unwrapped;
    type Wrapped;
}

trait Functor<U>: HKT<U> {
    fn fmap<F: FnOnce(Self::Unwrapped) -> U>(self, f: F) -> Self::Wrapped;
}

impl<A, U> HKT<U> for Maybe<A> {
    type Unwrapped = A;
    type Wrapped = Maybe<U>;
}

impl<A, U> Functor<U> for Maybe<A> {
    fn fmap<F: FnOnce(Self::Unwrapped) -> U>(self, f: F) -> Self::Wrapped {
        match self {
            Maybe::Just(x) => Maybe::Just(f(x)),
            Maybe::Nothing => Maybe::Nothing,
        }
    }
}

まとめ

「type Wrapped: Functor;」な部分がGAT(Generic Associated Types)なところ

それにしてもモナドが何なのかサッパリわからん

广告
将在 10 秒后关闭
bannerAds