C#中的单子理解语法

5
我曾在#haskell IRC聊天室逗留了几天,有人提到C#有用于执行单子推理的语法。这是什么意思?
如果我理解正确,单子推理只是一种按顺序进行bind操作的方法,这听起来有点像do符号?是这样吗?
问题是我在C#中没有看到这个。据我所知,IEnumerable 是一个单子,其中SelectMany是其bind函数,因为其签名是A -> IEnumerable 。稍微想象一下,我们可以做
from x in xs
from y in ys

这句话的意思是“转化为(我不是100%确定)”。
xs.SelectMany(x => ys.Select(y => y), (x, y) => ...)

但即使这是真的,我们把LINQ看作是一个单子推导语法,它仍然只适用于IEnumerable。在C#中我们有其他单子如Task,但是我们怎样在其上运用LINQ呢?可能在这个问题中许多假设都是完全错误的,因为我仍在尝试理解一些单子魔法的东西。如果我错了,请纠正我 :)
1个回答

10

LINQ查询语法只是语法糖,并不知道 IEnumerable<> 的任何内容,因此您可以将其用于其他事情。

如果您查看 C# 语言规范,它在第7.16.2节中描述了LINQ的查询表达式应如何转换。

C#语言没有指定查询表达式的执行语义。相反,查询表达式被转换为遵循查询表达式模式(§7.16.3)的方法调用。具体而言,查询表达式被转换为Where、Select、SelectMany、Join、GroupJoin、OrderBy、OrderByDescending、ThenBy、ThenByDescending、GroupBy和Cast等名称的方法调用。这些方法应具有特定的签名和结果类型,如§7.16.3所述。这些方法可以是正在查询的对象的实例方法,也可以是外部对象的扩展方法,并且它们实现查询的实际执行。

您的特定示例被描述为

带有第二个from子句和select子句的查询表达式

from x1 in e1
from x2 in e2
select v

is translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

因此,使用您示例中的变量名称,任何具有方法Treturned SelectMany(Func<Tx,Tys>, Func<Tx,Ty,Treturned>)xs都可以在语句中使用。
Treturned returned =
    from x in xs
    from y in ys
    select r;

这将在编译时完全编译。
Treturned returned = xs.SelectMany(x => ys, (x, y) => r);

如果xs上存在这样的方法,那么SelectMany就是任何时候都存在的。事实上,SelectMany适用于IEnumerable<>并不妨碍我们为其他类型配备具有相同名称的方法或扩展方法。

C#可以从它知道xs是什么以及从中查找xsSelectMany的参数类型来推断lambda的类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接