...与所有那些新的(如果我们计算IEnumerable并不是那么新)monad相关的东西?
interface IMonad<T>
{
SelectMany/Bind();
Return/Unit();
}
这将允许编写在任何monadic类型上运行的函数。或者它不是那么重要?
答案 0 :(得分:63)
考虑IMonad<T>
方法的签名必须是什么。在Haskell中,Monad类型类被定义为
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
将此直接转换为C#接口很棘手,因为您需要能够在一般IMonad接口的定义中引用特定的实现子类型(“m a”或ISpecificMonad<a>
)。好的,我们不会试图让(例如)IEnumerable<T>
直接实现IMonad<T>
,而是尝试将IMonad实现分解为一个可以传递的单独对象,以及特定的monad类型实例,什么需要把它当作monad(这是“字典传递风格”)。这将是IMonad<TMonad>
,此处的TMonad不是IEnumerable<T>
中的T,而是IEnumerable<T>
本身。但是等等 - 这也不行,因为例如Return<T>
的签名必须让我们从任何类型T到TMonad<T>
,对于任何 TMonad<>
。 IMonad必须被定义为类似
interface IMonad<TMonad<>> {
TMonad<T> Unit<T>(T x);
TMonad<U> SelectMany<T, U>(TMonad<T> x, Func<T, TMonad<U>> f);
}
使用假设的C#功能,允许我们使用类型构造函数(如TMonad&lt;&gt;)作为泛型类型参数。但是当然C#没有这个功能(更高级别的多态性)。您可以在运行时(typeof(IEnumerable<>)
)重新生成类型构造函数,但不能在不给它们参数的情况下在类型签名中引用它们。因此,除了-100点之外,实现这个“正确”不仅需要添加另一个普通的接口定义,而且需要对类型系统进行深入的添加。
这就是为什么对你自己的类型进行查询理解的能力被攻击(如果正确的魔术方法名称带有正确的签名,它们只是“神奇地”工作),而不是使用接口机制等。
答案 1 :(得分:-20)
Monads对.NET程序员来说并不重要。即使知道monad存在,你仍然可以构建LINQ框架。更重要的是,它看起来不会有任何不同。如果你考虑monads(Haskell),表达式树重写(Lisp),基于集合的操作(SQL),或者使用map / reduce来创建新类型(Ruby,Python),这无关紧要,最终的结果是会是一样的。
事实上,我甚至会说,monads对.NET开发人员来说是无用的。每当我看到基于monad的.NET库时,它总是比直接的C#或VB代码更冗长,更难以理解。原因很简单,像C#和VB这样的语言建立在比Haskell这样的语言更强大的构建块上。
Haskell特别需要使用monad来处理所有事情,因为这就是他们所拥有的一切。 Lisp中的宏或JavaScript中的动态类型也是如此。当你有一个单一的小马,那个技巧必须非常好。