モナドではない

大きな勘違いをしていたかも。

モナドの十分な要件って、

  • ある型aに対してそのコンテナとなる型M(a)が定義される
  • 関数unit_a:a→M(a)、bind_aa:M(a) → (a → M(a)) → M(a)が定義される*1
  • unit_aとbind_aaについてモナド則が成り立つ
    • 型aの要素xとf:a→M(a)となるfに対してbind_aa(unit_a(x), f) ≡ f(x)
    • M(a)の要素mに対してbind_aa(m, unit_a) ≡ m
    • M(a)の要素mとf:a→M(a), g:a→M(a)に対して、bind_aa(bind_aa(m, f), g) ≡ bind_aa(m, (fun x => bind_aa(f(x), g)))」

だと思ってたんだけど、「Javaで複合モナド - terazzoの日記」で定義したflattenって関数のシグネチャを見るとflatten:M(M(a))→M(a)ってなってて、つまり最低限unit_M:M(a)→M(M(a))のようにモナドモナドが作れる必要があるんじゃないかと思った。(さらに言うとM(M(M(a)))やM(M(M(M(a)))))や……)


最近自分が書いたやつで言えば、

となりOption以外はモナドといえるかどうか非常に怪しい。


Java上で単に処理のチェーンを作るだけの話であれば、M(M(a))が作れる必要性ってあんまり感じないんだけど、単なる自己関手なんとか対象というにはそういうのも必要なんだろうか。なんだろうな。


複合モナドとかいう前にまずちゃんとモナドの形にする必要があるのかも。

6/15追記

明示的にM(M(a))は作れなくても、m.bind(f).bind(g)みたいな形には出来ているので、つまり見る人の心の中にflattenがあればOKということにできないか。


実際に上のfizzbuzzの例で、ベースの型のIntegerを型パラメータTに書き換えるだけで、bindとunitから機械的にflattenを作れるし、そうやって特に意識することなく作ったflattenでflatten(messageOf(messageOf(1, "hoge"), "fuga")) = messageOf(1, "fugahoge")みたいな実行結果になるので、bindが定義されていれば実質flattenは存在するんだ(コード化されていないだけ)という風に考えられるんじゃないかと思った。


もう少し勉強したらまたちょっと直す。

*1:最低ラインとして型bは登場しない世界を想定