モナド
モナドはで構成されてい
また、モナドでpure
ありbind
、3つのモナドの法則に従う必要があります。
さて、C#でモナドをモデル化する1つの方法は、インターフェースを構築することです。
interface Monad<M> {
M<T> pure(T v);
M<B> bind(M<A> mv, Func<A, M<B>> f);
}
(注:簡潔で表現力豊かなものにするために、この回答全体を通して、コードに多少の自由を取ります。)
これで、具象実装を実装することにより、具象データガイプのモナドを実装できますMonad<M>
。たとえば、次のモナドを実装できますIEnumerable
:
class IEnumerableM implements Monad<IEnumerable> {
IEnumerable<T> pure(T v) {
return (new List<T>(){v}).AsReadOnly();
}
IEnumerable<B> bind(IEnumerable<A> mv, Func<A, IEnumerable<B>> f) {
;; equivalent to mv.SelectMany(f)
return (from a in mv
from b in f(a)
select b);
}
}
(意図的にLINQ構文を使用して、LINQ構文とモナドの関係を呼び出しています。ただし、LINQクエリをの呼び出しに置き換えることができることに注意してくださいSelectMany
。)
さて、モナドを定義できますIObservable
か?そのように見えるだろう:
class IObservableM implements Monad<IObservable> {
IObservable<T> pure(T v){
Observable.Return(v);
}
IObservable<B> bind(IObservable<A> mv, Func<A, IObservable<B>> f){
mv.SelectMany(f);
}
}
モナドがあることを確認するには、モナドの法則を証明する必要があります。これは些細なことではありません(Rx.NETに精通していないため、仕様だけで証明できるかどうかはわかりません)が、有望な出発点です。この議論の残りを容易にするために、この場合にモナドの法則が成立すると仮定しましょう。
無料のモナド
特異な「無料モナド」はありません。むしろ、無料のモナドはファンクターから構築されるモナドのクラスです。つまり、functorが与えられると、F
自動的にモナドF
(つまり、の無料のモナドF
)を導出できます。
ファンクター
モナドと同様に、ファンクターは次の3つの項目で定義できます。
- 単一の無制限の型変数でパラメーター化されたデータ型。
2つの操作:
pure
ファンクタに純粋な値をラップします。これはpure
モナドに似ています。実際、モナドでもあるファンクターの場合、2つは同一でなければなりません。
fmap
特定の関数を介して、入力の値を出力の新しい値にマッピングします。署名は次のとおりです。
F<B> fmap(Func<A, B> f, F<A> fv)
モナドと同様に、ファンクターはファンクターの法則に従う必要があります。
モナドと同様に、次のインターフェイスを介してファンクターをモデル化できます。
interface Functor<F> {
F<T> pure(T v);
F<B> fmap(Func<A, B> f, F<A> fv);
}
さて、モナドはファンクタのサブクラスなのでMonad
、少しリファクタリングすることもできます:
interface Monad<M> extends Functor<M> {
M<T> join(M<M<T>> mmv) {
Func<T, T> identity = (x => x);
return mmv.bind(x => x); // identity function
}
M<B> bind(M<A> mv, Func<A, M<B>> f) {
join(fmap(f, mv));
}
}
ここで、追加のメソッドを追加しjoin
、との両方のデフォルト実装を提供join
しましたbind
。ただし、これらは循環定義であることに注意してください。したがって、少なくとも一方をオーバーライドする必要があります。また、pure
はから継承されることに注意してくださいFunctor
。
IObservable
および無料のモナド
さて、モナドはのために定義されてIObservable
おり、モナドはファンクターのサブクラスであるため、のためにファンクターインスタンスを定義できなければなりませんIObservable
。定義は次のとおりです。
class IObservableF implements Functor<IObservable> {
IObservable<T> pure(T v) {
return Observable.Return(v);
}
IObservable<B> fmap(Func<A, B> f, IObservable<A> fv){
return fv.Select(f);
}
}
のためIObservable
に定義されたファンクターができたので、そのファンクターから無料のモナドを構築できます。そして、それが正確IObservable
にフリーモナドとどのように関係するのか、つまり、からフリーモナドを構築できるということIObservable
です。
Cont
唯一、私は自由にモナドを介して発現することができないことを示唆し見てきましたモナドされ、一つはおそらくFRPができると仮定することができます。他のほとんど何でもできるように。