对IEnumerable <T>以外的类型(monads?)进行操作的LINQ查询表达式 - 可能的用途?

sta*_*ica 13 c# linq monads ienumerable computation-expression

我正在阅读Tomas Petricek和Jon Skeet撰写的真实函数式编程书,我很难消化关于计算表达式1)(又名monads)的部分.

通过本书,我了解到 - 与我之前的经验相反 - LINQ查询表达式不仅限于此IEnumerable<T>,而且可以在其他自定义类型上工作.这对我来说似乎很有趣,我想知道是否存在查询表达式语法(from x in ... select ...)非常适合的情况.


一些背景信息:

显然,这种自定义类型称为计算类型,它们被描绘为与Haskell中的monad基本相同.我从来没有能够理解monad究竟是什么,但根据这本书,它们是通过两个叫做bindreturn的操作来定义的.

在函数式编程中,这两个操作的类型签名将是(我认为):

//    Bind      :    M<A'> -> (A' -> B') -> M<B'>
//
//    Return    :    A' -> M<A'>
Run Code Online (Sandbox Code Playgroud)

Mmonadic类型的名称在哪里.

在C#中,这对应于:

Func< M<A>, Func<A,B>, M<B> >   Bind;

Func< A, M<A> >                 Return;
Run Code Online (Sandbox Code Playgroud)

事实证明,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));
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以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!
Run Code Online (Sandbox Code Playgroud)

当然这个例子不是很有用,但是它演示了如何使用查询表达式来处理其他事情,而不是使用集合,例如用某种类型包装和解包值.


题:

上面的计算类型似乎不太有用.因此我想知道,除了处理集合之外还有什么可以使用LINQ查询表达式?


1)第12.4节:"引入替代工作流程",从第334页开始.

sta*_*ica 4

尽管我不喜欢这样做(因为这感觉有点像作弊),但我想这次我必须回答我自己的问题。

\n\n

对此我又想了一些。我的问题有点na\xc3\xafve。归根结底,LINQ 查询表达式(例如………… fromin是其他更基本语法之上的语法糖。whereselectforeach

\n\n
    \n
  • foreach适用于任何实现IEnumerator<T> GetEnumerator()方法的东西。IEnumerable<T>恰好满足这个条件。

  • \n
  • 类似地,LINQ 查询表达式根据一些明确定义的规则进行转换,例如from x in xs where x > 0 select -x变为xs.Where(x => x > 0).Select(x => -x)。只要某种类型实现了部分或全部查询运算符方法,该类型就可以与 LINQ 一起用于几乎任何目的。

  • \n
\n\n

我剩下的问题是,除了处理集合之外,LINQ 的实际用途是什么?我认为答案是“很少有其他事情”,因为 LINQ 查询表达式的结构非常严格。你总是需要from……in部分。似乎select……也总是需要的。如果结果表达式的“语言”不适合特定的潜在场景,则任何其他关键字(let, orderby,groupby等)都不会改善这种情况。LINQ 的设计非常明确,只考虑了一个目标,即数据查询,而由此产生的语法实际上对 LINQ 的限制超出了可能的必要范围。

\n\n

我将 LINQ 用于查询数据以外的目的的可能性与 F# 计算表达式的可能性进行了比较,它们似乎更灵活,因为没有那么多必需的关键字。这往往使它们适用于更多场景。

\n