[Haskell]モナド則について

モナドを使うのに圏論の知識なんて不要だし、モナド則なんか意識する必要はない、というのはその通りだと思う。ぼく自身、圏論にはあまり興味は無いし深入りする気はないのだが、Haskellの珍妙な演算子と珍妙な関数名と謎のエラーメッセージを理解してコンパイルの通るコードを書くためには、やはりモナドについて基本的な理解が必要だと感じた。(C言語ではじめてポインタを使ったときの感覚に近いかも。)

モナドにまつわる演算子・関数まとめ

圏論の記号でいうと、return は η 、join は μ に相当する。
両者は双対の関係にあり、return は一皮かぶせ、join は一皮むく。

return と >>= に関するモナド

Haskellにおけるモナド則とは、return と >>= (bind) に関するルールであり、return の左単位律と右単位律、および >>= の結合律である。しかし、単位律も結合律も非対称な形になり、いまひとつ分かりにくい。具体例として、Maybeモナドの例を図示する。


   斜め上に上がる関数 f の入り口を持ち上げて真横にして、x を持ち上げた m x を渡すのは、
   関数 f に x に渡すのと同じ。


   まっすぐ持ち上げる関数である return の入り口を持ち上げると、
   何もせずに素通りする関数になる。


   ① 関数 f の入り口を持ち上げて真横にして m x を渡した戻り値を、
    関数 g の入り口を持ち上げて真横にして渡した戻り値
   ② 関数 g の入り口を持ち上げて真横にして 関数 f の出口とつなげた関数の
    入り口を持ち上げて真横にして m x を渡した戻り値
   ①と②は等しい。

return と join に関するモナド

いっぽう、圏論におけるモナド則は、Haskell の言葉でいうと return と join に関するルールである。こちらのほうが見た目にはすっきりしていて分かりやすい。ただ、これが単位律なのか?結合律なのか?といわれるとちょっと首をかしげたくなる。具体例として、Listモナドの例を図示する。


   モナドの内側に一皮かぶせてから一皮むいても、元のモナドと同じ。
   モナドの外側に一皮かぶせてから一皮むいても、元のモナドと同じ。


   三重のモナドを内側から一皮むいてさらに一皮むいても、
   三重のモナドを外側から一皮むいてさらに一皮むいても、同じ一重のモナドになる。

圏論モナド則とHaskellモナド則の違い

  • 圏論モナド則は return と join に関するルール
  • Haskellモナド則は return と >>= に関するルール
  • 圏論モナド則はモナドの皮をかぶせる/むくことについて述べている
  • Haskellモナド則はモナドの皮をむいて関数に渡して皮をかぶせることについて述べている
  • 両者が等価なのか等価ではないのかよく分からない