Creatable a => a -> IO b

Haskellと数学とちょびっと音楽

プログラマであるあなたが圏論を学んで得られる事、得られない事

Haskellと数学とちょびっと音楽」なんていうシャレオツなサブタイをブログに付けてるのは誰ですか? 俺だよー!

大体、Haskell関連のコミュニティに顔を出していると、 数学科出ましたーとか、物理専攻ですー、とか、そーいう人がわりと多いのですが、 僕は「勉強なんて出来ないんジャー・レッド」だったので、サブタイトルに「数学」なんて入れつつも、 数学の話はほとんど出来なかったりとか出来たりとか・・・結局Haskellの記事しか書いてないですね、はい。

ただ、どちらかというと、Haskellでも処理系どうのとか、パフォーマンス云々とか、 そういう話より型システムでどうやって抽象化するかーみたいな、そういう話のほうがおもしれーとか思ったりしたので、 気づいたら圏論なんかはガジガジしてまして、多少の自己流の知識があったりとかなかったりとかしてるのです。

純粋関数型やらHaskellやらがメジャー化していくのに伴って、 「副作用」やら「関数型」と同時に「圏論」もバズワード化してきているような気がしているので、 今回は、圏論によって何が出来るか、何が出来ないか、雰囲気的な事をまとめようと思います。

圏論の基礎の基礎の基礎くらいの話

まず、圏論ってどんな事やんの?っていうほわほわっとした感覚を掴んで頂くために、 圏論のイロハのイの半分くらいまで説明しようかと思います。 こいつらどんな事考えてるのかなーっていうヒントにはなるんじゃないかなーと、そんな感じです。

あー、ちゃんと図式書くの面倒なのでAAで我慢してね。

下の図の、矢印の頂点A, B, Cを「対象(Object)」といいます。
下の図の、矢印f, gを「射(Arrow)」といいます。

         f         g
    A ------> B ------> C

射と射をくっつける「射の合成(composite)」という計算ができ、 fからgへの結合をg○fみたいに書きます。

             g○f
    +-------------------+
    |                   |
    |   f          g    v
    A ------> B ------> C

あと、全ての対象に自分から自分への射、恒等射Id_Xがあります。 これわりとミソです。

        Id_A
    +---------+
    |         |
    |         |
    A <------ + 

んで、射の合成には結合則ってのがあります。 下の図のAからDへの矢印はどの経路を通っても同じ結果にならなくてはいけません。

             g○f
    +-------------------+
    |                   |
    |   f          g    v    h
    A ------> B ------> C ------> D
              |                   ^
              |                   |
              +-------------------+
                       h○g

あと、恒等射には単位元則があります。 下の図の、f○Id_AとId_B○fはいずれもfと同じにならなくてはいけません。

                            Id_B
                        + ------- +
                        |         |
                   f    |         |
    + ------> A ------> B <------ +
    |         |
    |         |
    + ------- +
       Id_A

んで、これらの道具立てがひと通り揃ったものを「圏」と呼びます。 基本的には、このルールに則って色んなものの間に矢印を引き、 その矢印の関係性「だけ」を使って性質や特徴を導いていくのが圏論です。

で、圏論がプログラミングに何で重要なのかというと、 関数プログラミングの型システムがデカルト閉圏という圏と対応するからです。

単純に、

  • 型が対象
  • 関数が射
  • 関数合成が射の合成
  • id関数が恒等射

と対応します。これが実際に圏となる事は、上記の道具立てがちゃんと整っている事を一つ一つ確認してみればわかるでしょう。

Haskell圏論の密接な関係

とまぁ、圏論の入門以前的な話をしましたが、 本エントリの主題は圏論入門ではなく、この話をさらに突き詰めていくとどうなるのか、という事なので、 本格的な圏論入門は書きません。

Haskellのもっとも身近な圏論由来の概念はFunctor(関手)でしょう。 圏論において関手とは圏から圏への対応付けの事を言います。 HaskellのFunctorはその中でも、自己関手という特殊な関手を実装に落とし込んだものです。

我らがモナドも勿論、圏論由来の概念です。 「自己関手の圏におけるモノイド対象だぜ、フフフ」ってのもありますが、 クライスリ圏という圏を勉強すると、(>>=)演算子の正体が見えて来たりします。

さらに、LensやFree、Yonedaといった最近名前を聞く抽象的なライブラリも、 バックグラウンドに圏論があるようですが、残念ながらこのエントリを書いてる段階で、 ちゅーんさんの知識はそこまで進んで無いのです(´・ω・`)
わりと必要に迫られてる気がするので、しばらくすると解る人になってます。 その頃になったら聞いて下さい、ドヤ顔で説明します。はい。

で、

fmap関数がFunctorのメソッドである事からわかるかもしれませんが、 Listのmap関数も圏論の視点から説明する事は出来ますし、 fold関数を圏論で一般化すると、catamorphismという概念が出てきます。 また何気なく作った多相関数が「自然変換」と呼ばれる形になっている事は多々ありますし・・・ 後はあんまり意識する事は無いですが、代数的データ型自体もF始代数と呼ばれる圏論の概念として表現できまして、 その事は例えば、型レベルで計算が出来るという話にもつながってきます。

とか、とか、こんな感じ?

圏論を学んで得られる事、得られない事

と、偉そうにタイトルを掲げてみたんですけど、ここまで書いて、いざ本題に入ろうとしたら、あの、あれです、 どうしてもポエーっとなってしまって(´・ω・`)←今こんな顔してます
というわけで、ここに書かれている内容はかなーり独断と偏見にまみれてると思ってお読みください。☆(ゝω・)vてへっ

とりあえず、間違いなく言える事として、銀の弾丸にはなり得ないという事だけははっきりと述べておきましょう。

期待しても良い事

知識としては、FunctorやMonad等、 Haskellプログラミングによく現れる概念に対する、数学的な背景が得られます。 実の所「道具として使えてはいるけど、結局モナドって何だか良くわかってないよね?」みたいな、 そんな「わかってんだかわかってないんだかわかんないもやもや感」を解消出来るのが、 圏論を学んで一番うれしい事かもしれません。

後はかなり実感的な部分で確証がある話では無いのですが、圏論の概念が対応しているのは型システムなので、 Haskellプログラミングに重要な「型レベルで考える」感覚は養えるように思います。

あとは、ちゅーんさんの場合はもともと数学スキルが絶望的なので、 数学の基本的な感覚を身につけるのに圏論のお世話になりました。 ってか現在進行形でなってます。本当にありがとうございます。

あんまり期待できない事

だいたい、Haskellで使う圏論的な概念をプログラムで使う際に必要な公理やら定理の類は、「〜則」みたいな形でプログラムに落としこまれているので、 よほど新規性の高い事をやらないと、圏論で得た知識をそのままの形でプログラミングに応用出来る事はあまり無いように思います。

それから、抽象度の高い高度なライブラリを設計するのに役立つとは言いますが、 圏論を学んで、実際にそのレベルで圏論を応用出来る才能のある人は、限られているように思われますぅ・・・。 但し、型設計のための貴重な判断材料にはなり得るので、全否定する程では無いかもですね。

あと、基本的には応用範囲が型レベルですから、 値レベルにまで掘り下げないと解決できない問題には無力です。実に無力なのです。

まとめ的な何か

というわけで、「圏論」のバズワード化を懸念して、初学者の立場からあれこれと纏めてみました。

自己流で色々とかじってる感じ、決して表面をなぞっただけで人に説明できるほど簡単な学問ではありませんが、 微積分が出来ないどころか分数の四則演算でテンパるちゅーんさんでもこのくらいの内容の話は出来ますので、 あなたの知りたい事、やりたい事にあわせて、本格的に学びはじめて見ても良いのではないでしょうか?か?