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究竟是什么,但根据这本书,它们是通过两个叫做bind和return的操作来定义的.
在函数式编程中,这两个操作的类型签名将是(我认为):
// 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.
使用这些知识,我现在可以编写一个不是 的自定义计算类型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页开始.
尽管我不喜欢这样做(因为这感觉有点像作弊),但我想这次我必须回答我自己的问题。
\n\n对此我又想了一些。我的问题有点na\xc3\xafve。归根结底,LINQ 查询表达式(例如………… from)in是其他更基本语法之上的语法糖。whereselectforeach
foreach适用于任何实现IEnumerator<T> GetEnumerator()方法的东西。IEnumerable<T>恰好满足这个条件。
类似地,LINQ 查询表达式根据一些明确定义的规则进行转换,例如from x in xs where x > 0 select -x变为xs.Where(x => x > 0).Select(x => -x)。只要某种类型实现了部分或全部查询运算符方法,该类型就可以与 LINQ 一起用于几乎任何目的。
我剩下的问题是,除了处理集合之外,LINQ 的实际用途是什么?我认为答案是“很少有其他事情”,因为 LINQ 查询表达式的结构非常严格。你总是需要from……in部分。似乎select……也总是需要的。如果结果表达式的“语言”不适合特定的潜在场景,则任何其他关键字(let, orderby,groupby等)都不会改善这种情况。LINQ 的设计非常明确,只考虑了一个目标,即数据查询,而由此产生的语法实际上对 LINQ 的限制超出了可能的必要范围。
我将 LINQ 用于查询数据以外的目的的可能性与 F# 计算表达式的可能性进行了比较,它们似乎更灵活,因为没有那么多必需的关键字。这往往使它们适用于更多场景。
\n| 归档时间: |
|
| 查看次数: |
1060 次 |
| 最近记录: |