2016-12-16 3 views
4

だから、私はf#の計算式やカスタムビルダーにかなり慣れてきました。私は日々の仕事の大部分をC#で行う必要がありますが、LINQ式は自分のモナド/モノイドで使いたいと思っています。 f#のZeroメソッドへのC#アナログがあるかどうか誰かが知っていますか?f#のbuilder.Zero()のLINQに相当しますか?

Relevant f# docs

ここで私はF#で行うものです:

type OptionBuilder() = 
    member x.Bind(v,f) = Option.bind f v 
    member x.Return v = Some v 
    member x.ReturnFrom o = o 
    member x.Zero() = Option.None 

let option = OptionBuilder() 

// Example usage (I want something similar from c#) 

let t : Option<int> = 
    option { if false then return 5 } 

答えて

10

私はあなたがここに求めている正確に何か分からないが、私はそれに打撃を与えるでしょう。問題を明確にすることを検討してください。モナドワークフローの無いelseifにC#で

同等である:

from a in b 
where c(a) 
select a 

論理的これは(戻り、ゼロ、あなたのバインドを使用して)と等価である

Bind(b, a => c(a) ? Return(a) : Zero) 

しかし、C#はwhere節をSelectMany(これはC#がBindと呼ぶものです)に引き下げません。 C#が要するに

Where(M<T>, Func<T, bool>) 

への呼び出しにクエリ理解にWhere句を低下させる:C#は、クエリの内包の形態の任意の単項ワークフローを有します。 Select、SelectMany、Whereなどのどのモナド型のメソッドでも、理解で使用できます。しかし、それは明示的なゼロを持つ付加的なモナドに実際に一般化されません。むしろ、 "Where"は上記のバインド操作のセマンティクスを持つことが期待されます。項目が述語と一致する場合は単一の値を最後にバインドし、そうでない場合はゼロの値をバインドするのと同じ効果があります。

一般的には、「どこで」シーケンスがそうですか。あなたが[a、b、c]を持っていてbをフィルターにかけたいのであれば、それは[[a]、[]、[c]]を連結するのと同じです。もちろん、これらの小さなシーケンスを実際に構築して連結することは、狂って効率的ではありません。 の効果は同じである必要がありますが、実際の操作はずっと効率的です。

C#は、yieldを介したシーケンスモナドとクエリの解説、await経由の継続コモンドなど、非常に特殊なモナドをサポートするように実際に設計されています。 Haskellのように、任意のモナディックワークフローを可能にするようには設計していませんでした。

あなたの質問にお答えしますか?

エリックの優れた答えと並ん
2

、ここではいくつかのコードです:

 var result = 
     from value in Option.Some(5) 
     where false 
     select value; 

C#のLINQの理解は、対応する拡張メソッド、Whereを探します。ここでの実装例は次のとおり

public static Option<T> Where<T>(this Option<T> option, Func<T, bool> condition) 
     { 
      if(option is None || !condition(option.Value)) 
       return None; 

      return option; 
     } 

Where自体は、ゼロケースを定義しなければなりません。

+2

実際、 'where'は結果がゼロモードであるというセマンティクスを持たなければなりません。それは良い洞察です。これから私たちは次のようなものを見ることができます: 'IObservable 'モナドのゼロは 'OnNext'を決して呼び出さない観測可能なシーケンスでなければなりません。それで、小さなパズル: 'Task 'のゼロは何ですか? –

+0

結果を論理的に返すことはできないため、選択肢は1つだけです: 'Task.FromCanceled(new CancellationToken(true)) ' – Asti

+0

これは妥当な選択ですが、唯一の選択ではありません。他の可能性は、例外の完了を持つ別のタスク、または永遠に実行され、完了しないタスクです。 –

関連する問題