11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RustでFunctor書いてみる

Last updated at Posted at 2020-12-27

少し前に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

Haskell
data Maybe a = Nothing | Just a

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

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

#Functor

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

> fmap (+3) Nothing
Nothing

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

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

とりあえず書いてみる

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

テストしてみる

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

これって Option

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

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

Haskell
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
Rust
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)]

を頭に追加して

Rust
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ないけど、関連型を駆使して書けるらしい

Rust
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<B>: Functor;」な部分がGAT(Generic Associated Types)なところ

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

11
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?