私はTomas Petricek と Jon Skeet によるReal-world Functional Programmingという本を読んでいますが、計算式1) (別名モナド) のセクションを理解するのに苦労しています。
この本を通じて、以前の経験とは対照的に、LINQ クエリ式は に限定されずIEnumerable<T>
、他のカスタム型でも機能することを学びました。これは私にとって非常に興味深いことであり、クエリ式の構文 ( from x in ... select ...
) が適しているシナリオがあるかどうか疑問に思っています。
背景情報:
どうやら、そのようなカスタム型は計算型と呼ばれ、Haskellのモナドと本質的に同じものとして描かれています。私はモナドが何であるかを正確に把握することはできませんでしたが、本によると、それらはbindとreturnと呼ばれる 2 つの操作によって定義されます。
関数型プログラミングでは、これら 2 つの操作の型シグネチャは次のようになります (私が思うに):
// Bind : M<A'> -> (A' -> B') -> M<B'>
//
// Return : A' -> M<A'>
はM
モナド型の名前です。
C# では、これは次のようになります。
Func< M<A>, Func<A,B>, M<B> > Bind;
Func< A, M<A> > Return;
LINQ Enumerable.Select
(射影演算子) は、バインド操作とまったく同じシグネチャを持っていることがわかりM := IEnumerable
ます。
私のカスタム LINQ 計算タイプ:
この知識を使用して、次のようなカスタム計算タイプを記述できるようになりました IEnumerable
。
// my custom computation type:
class Wrapped<A>
{
// this corresponds to the Return operation:
public Wrapped(A value)
{
this.Value = value;
}
public readonly A Value;
}
static class Wrapped
{
// this corresponds to the Bind operation:
public static Wrapped<B> Select<A, B>(this Wrapped<A> x, Func<A,B> selector)
{
return new Wrapped<B>(selector(x.Value));
}
}
Wrapped<T>
これで、LINQ クエリ式で使用できるようになりました。たとえば、次のようになります。
Wrapped<int> wrapped = new Wrapped<int>(41);
Wrapped<int> answer = from x in wrapped // works on int values instead
select x + 1; // of Wrapped<int> values!
もちろん、この例はあまり役に立ちませんが、クエリ式を作成して、コレクションを操作する以外のことを行う方法を示しています。たとえば、値を何らかの型でラップおよびラップ解除するなどです。
質問:
上記の計算タイプはあまり役に立たないようです。したがって、LINQ クエリ式を利用する (コレクションの処理以外に) 他にどのような合理的な用途があるのでしょうか?
1)セクション 12.4:「代替ワークフローの紹介」、334 ページから。