Freeモナドとリアクティブエクステンションはどのように相関しますか?


14

私はLINQがRx.NETに進化したC#のバックグラウンドから来ましたが、FPには常に興味がありました。F#でモナドといくつかのサイドプロジェクトを紹介した後、次のレベルに進む準備ができました。

さて、Scalaの人々からの無料のモナドに関するいくつかの講演と、HaskellまたはF#での複数の記事の後、理解がIObservableチェーンに非常に類似していることを理解するための通訳付き文法が見つかりました。

FRPでは、チェーン内に留まる副作用や障害を含む、より小さなドメイン固有のチャンクから操作定義を作成し、一連の操作と副作用としてアプリケーションをモデル化します。無料のモナドでは、私が正しく理解していれば、ファンクターとして操作を行い、coyonedaを使用してそれらを持ち上げることで同じことを行います。

針をアプローチのいずれかに向けて傾ける両方の違いは何ですか?サービスまたはプログラムを定義するときの基本的な違いは何ですか?


2
問題について考える興味深い方法があります... FRPは、通常そのように定式化されていなくても、モナドと見なすことができます。ほとんどの(すべてではありませんが)モナドは、フリーモナドと同型です。Cont唯一、私は自由にモナドを介して発現することができないことを示唆し見てきましたモナドされ、一つはおそらくFRPができると仮定することができます。他のほとんど何でもできるように。
ジュール

2
LINQとRx.NETの両方のデザイナーであるErik MeijerによるとIObservable、継続モナドのインスタンスです。
ヨルグWミットタグ

1
現時点では詳細を検討する時間はありませんが、RX拡張とフリーモナドアプローチはどちらも非常に似た目標を達成しますが、構造が若干異なる可能性があると思います。RXオブザーバブル自体がモナドである可能性があり、その後、オブザーバブルを使用して、フリーモナド計算を1つにマッピングできます。これは、「フリーモナド」の「フリー」の意味です。あるいは、関係はそれほど直接ではなく、あなたはそれらが同様の目的でどのように使用されているかを拾っているだけかもしれません。
ティコンジェルビス16

回答:


6

モナド

モナドはで構成されてい

  • endofunctor。ソフトウェアエンジニアリングの世界では、これは単一の無制限の型パラメーターを持つデータ型に対応していると言えます。C#では、これは次の形式になります。

    class M<T> { ... }
    
  • そのデータ型で定義された2つの操作:

    • return/ pureは「純粋な」値(つまり、T値)を受け取り、それをモナドに「ラップ」します(つまり、M<T>値を生成します)。returnはC#の予約済みキーワードなのでpure、これからこの操作を参照するために使用します。C#では、次のpureような署名を持つメソッドになります。

      M<T> pure(T v);
      
    • bind/ flatmapは、単項の値(M<A>)と関数を取りますff純粋な値を取り、単項値(M<B>)を返します。これらからbind、新しいモナド値(M<B>)を生成します。 bind次のC#署名があります。

      M<B> bind(M<A> mv, Func<A, M<B>> f);
      

また、モナドで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です。


カテゴリ理論の洞察力のある理解!私は、それらがどのように作成されるかではなく、機能的なアーキテクチャを構築し、どちらかでエフェクト合成をモデリングするときの違いについて話したものを求めていました。FreeMonadは、具体化された操作用のDSLを構築するために使用できますが、IObservablesは時間の経過に伴う離散値に関するものです。
MLProgrammer-CiM

1
@ MLProgrammer-CiM、今後数日間でそれに関する洞察を追加できるかどうかを確認します。
ネイサンデイビス

無料のモナドの実用的な例が
欲しい
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.