射っていうのはscalaだと単なる関数だし、関手はmap、モナドはflatMapなだけです。これのどこが難しいというのでしょう。
内容について考えてみよう。
圏の定義?
trait Cat { type A type B def f:A => B } trait Cat { type A type B type C def f:A => B def g:B => C def f_g:A => C = f andThen g }
ここで定義されているCatはただの1本の射であって圏とは言い難い。hom setを定義したというのならまだわかるが、ScalazのHomとは似ているが違う定義だ。具体的に言うと、Homは1本の射fではなく、射を表す型であるCが定義されている。
簡単に考えるのであれば対象が型で射が普通のScalaの関数である圏を考えるのが一番だが、Scalazによればそれは以下の定義で与えられる。
implicit val Function1Category: Category[Function1] = new Category[Function1] { def id[A] = a => a def compose[X, Y, Z](f: Y => Z, g: X => Y) = f compose g }
住所圏からOption圏への関手?
さて、先ほど「圏とは言い難い」という表現をしたのだけど、これは「関数1つからなる圏も考えられる」という事実を考慮してのことだ。可算無限歩くらい譲れば先ほどのCatはそれを表現しているとも考えられる*1。
これが関手といわれるものです。住所圏からOption圏への関数合成みたいなものですね。
ここでいう住所圏が「住所 => 郵便番号という関数1つからなる圏」、Option圏が「Option[住所] => Option[郵便番号]という関数1つからなる圏」とすれば、「mapは住所圏からOption圏への関手だ」という説明で問題はない*2 *3。しかし、関数型言語を使う場合に大抵の場合はこのような特殊な圏を考えることは少ないだろう。すべての型が対象、すべての関数が射、という圏で話を進めた方が一般的だし混乱は少ない。
flatMapがモナド?
モナドは関手(map) + flattenと同じ事です。
flatMapがmapとflattenを使って定義されるというのは正しい。問題は「> 関手はmap、モナドはflatMap」かどうかということだが、ここは微妙なとこだ。
というのは、モナドは関手の一種だからだ。Scalaの関手とモナドについてざっくり整理すると、以下のようになる。
さらに本格的な話に興味があれば、Scalazのコードを読むといいだろう。
とは言え、mapとflatMapが分かれば実用上問題がないというのはその通りで、それ以上圏や関手、モナドについて踏み込んで厳密に理解する必要はないと言える。「圏論とかモナドなんて不要だからscalaにおける要点だけ説明してみた」ってことあれば全く同意である
追記
ご本人からコメントがつきましたので、一応回答を。
rirakkumya ぼくは単に「モナドの事をscala”で"説明」したかっただけなのですが、「圏論とかモナドなんて不要だから〜」というのは論点がずれてないですか? scalaの要点なんて正直どうでも良いです。
@rirakkumya さんの圏論への愛情は理解できるが、元のエントリは上述したように圏やモナドの説明としては不適切だ。使えればいいのだから学術的な定義などどうでもいいという主張も理解できるのだが、圏論から学術的な厳密さを引いてしまうと圏論ではなくなってしまう*6。それはもはや単なるmap関数とflatMap関数の説明だ。
もう少し背景を補足すると、 @rirakkumya さんは関手的データモデルに興味を持っており、過去にもそれを表現しようとしていたことが伺える。そういう背景から判断して、上で書いた「関数1つからなる圏も考えられる」という立場に立ってこの説明を書いたというのは間違いないだろう。しかし、そうすると注釈欄にも書いたようにmapは自己関手ではなくなるため、flatMapをモナドと見なすことはできない。