... 与所有这些新的(如果我们算上 IEnumerable 的话就不是那么新)monad 相关的东西?
interface IMonad<T>
{
SelectMany/Bind();
Return/Unit();
}
这将允许编写在任何单子类型上运行的函数。或者它不是那么重要?
想想IMonad<T>
's 方法的签名必须是什么。在 Haskell 中,Monad 类型类定义为
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
将其直接转换为 C# 接口很棘手,因为您需要能够ISpecificMonad<a>
在通用 IMonad 接口的定义中引用特定的实现子类型(“m a”或 )。好的,我们不会尝试(例如)直接IEnumerable<T>
实现IMonad<T>
,而是尝试将 IMonad 实现分解为一个单独的对象,该对象可以与特定的 monad 类型实例一起传递给任何需要将其视为 monad 的对象(这是“字典传递风格”)。这将是IMonad<TMonad>
,这里的 TMonad 将不是 T in IEnumerable<T>
,而是IEnumerable<T>
它本身。但是等等——这也行不通,因为Return<T>
example 的签名必须让我们从任何类型 T 到 a 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<>)作为泛型类型参数。但是当然 C# 没有这个特性(更高种类的多态性)。您可以在运行时(typeof(IEnumerable<>)
)具体化类型构造函数,但不能在不给它们参数的情况下在类型签名中引用它们。因此,除了 -100 分之外,“正确”实现这一点不仅需要添加另一个普通接口定义,还需要对类型系统进行深度添加。
这就是为什么对您自己的类型进行查询理解的能力有点被破解(如果存在具有正确签名的正确魔法方法名称,它们只是“神奇地”工作)而不是使用接口机制等。
Monad 对 .NET 程序员来说根本不重要。即使不知道 monad 的存在,您仍然可以构建 LINQ 框架。更重要的是,它看起来并没有什么不同。无论您是从 monads (Haskell)、表达式树重写 (Lisp)、基于集合的操作 (SQL) 还是使用 map/reduce 创建新类型(Ruby、Python)的角度来思考,都没有关系,最终结果是会是一样的。
事实上,我什至会说 monad 对 .NET 开发人员完全没用。每次我看到一个基于 monad 的 .NET 库时,它总是比直接的 C# 或 VB 代码更冗长且更难理解。原因很简单,像 C# 和 VB 这样的语言是建立在比 Haskell 等语言更强大的构建块上的。
Haskell 尤其需要对所有事情都使用 monad,因为这就是他们所拥有的一切。Lisp 中的宏或 JavaScript 中的动态类型也是如此。当您拥有一匹特技小马时,该特技必须非常好。