読者です 読者をやめる 読者になる 読者になる

だらだらしてたいなぁ

ずっとゲームしながらだらだらしてたいけど、がんばってブログ書いてみた

圏論とかモナドなんて簡単だからscalaを使って説明してみた

圏論 scala

はじめに

関数型といえばモナドモナドといえば難しいという事が巷で言われていますが、いきなりモナドを理解しようとするから難しく思えるだけで、圏論から順序を追って理解していけば全然難しく無いんだよって事を分かって貰えればいいなぁと思い書いて見ることにしました。

ただ、圏論といっても適用範囲がとっても広く、応用編になると分けわかんなくなってくるので、ここではプログラミング分野に特化したFP(functional programing)圏論*1について書きます。

また、説明を簡単にする為に細かい部分をいろいろ省略しています。学術的な定義としては正確ではないので、このエントリの説明は大体合ってる位の気持ちで読んでくださいね。

尚、ぼくは圏論の詳しい事はさっぱり分からないので、学問的な話を振られても回答できませんキリッ

圏ってなんなの?

圏論と言えば、圏です。
圏って何なのかというと、対象(object)と射(arrow)で構成され、対象どうしが射で接続されているものが集まったグループです。対象は実体が無いラベルのようなものと理解しておいてください。はラベル同士を接続します。対象Aと対象Bが射fで結合されているとすると、f:A -> Bと書くことができます。scalaで書くと以下のようにそのまま書けます。

また、射同士も結合則にしたがって合成する事ができます。例えば、対象Aと対象B、対象Cが存在し、AとBが射f、BとCが射gで接続されているとすると、 gとfが合成できます。scalaだとこうなります。

結合


射のお尻と別の射の頭が同じラベル(対象)であれば合成可能です。

で、それが何の役に立つの?

それじゃ、お仕事で使うような例で書いてみます。住所から郵便番号を取得する仕様を圏を使って定義してみましょう。住所圏ですね。

住所圏イメージ

f:id:rirakkumya:20130331130710p:plain:w200

scalaで書いてみます。シンプルにする為に抽象化はしません。

住所圏

住所と郵便番号を対象として定義し、case classとStringを割り当て、射(def)でつなげました。簡単なので説明はいりませんね。
では、使ってみましょう。住所をzip射に適用すると郵便番号に変換されます。

それが関手(functor)なんだよ

ここで、住所があるか無いか分からない場合について考えてみましょう。scalaだとOptionを使いますよね。でも、Option型をさっきの住所圏に適用するには型が合いません。じゃどうするか。少しでもscalaをやったことがあれば分かりますね。mapを使います。それでは書いてみましょう。

これが関手といわれるものです。住所圏からOption圏への関数合成みたいなものですね。このコードを少し変形して合成されている事が分かるコードを書いてみます。

住所 => 郵便番号を渡すとOption[住所] => Option[郵便番号]が返ってきてますね。

また住所が複数あった場合でも、同じzip射が使えます。OptionをListに変えてみましょう。

モナドさんだけ日本語ついてなくて可哀想

さてここで、住所圏のzip射が複数の値を返す場合を考えてみましょう。住所が県や市までだった場合、郵便番号が沢山返ってきますから。scalaで書いてみます。

郵便番号が沢山返ってくるパターンを定義して、関手(map)に適用してみました。でもこれだと、List[郵便番号]が欲しいのにList[List[郵便番号]]が返ってますよね。これを意図通りに返す為にモナドを使います。モナドscalaで扱う時はflatMapです。

はい、これで欲しいものが返ってきました。scalaの立場からみると、モナドは関手(map) + flattenと同じ事です。

まとめ

  • 関手は射の変換先がコンテキスト(ListやOption)にくるまれていない時に使う。
  • モナドは射の変換先がコンテキスト(ListやOption)にくるまれている時に使う。

射っていうのはscalaだと単なる関数だし、関手はmap、モナドはflatMapなだけです。これのどこが難しいというのでしょう。
まぁ確かにモナドの応用編になってくると多少難しくなって来ますが、ここまで理解できてればそんなに難しくありません。

モナドが難しいっていうのは思い込みと、教える人が悪いだけです。いきなりモナドではなく、圏から順を追っていけばすんなり理解出来ると思います。
自分でモナドを作る場合はモナド則とか考えないといけませんが、使う分には気にしなくて大丈夫です。

あと、そもそもscalaが分かんないって人は以下の本を読んでみてください。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!


Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版

*1:勝手にそう呼んでます