大きな勘違いをしていたかも。
モナドの十分な要件って、
- ある型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)))))や……)
最近自分が書いたやつで言えば、
- 「これはモナドですか? - terazzoの日記」や「続・比較モナド - terazzoの日記」のOption
- Option
- bind((Option
- 「比較モナド - terazzoの日記」のComparisonResult
- 「数値のFizz、Buzz等への変換を、Javaで通常より直感的に表現したい - terazzoの日記」のAssociation
- 数値しか取れないのでNG
- (6/15追記)但しNumberAssociationをPlainAssociation
とかに直して任意の型を取れるようにすればM(M(a))を作れる
- 「http://d.hatena.ne.jp/terazzo/20110319/1300568176」のTemplate
- unitがSymbolしか取れないのでNG
となり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は登場しない世界を想定