... with all those new (and not so new if we count IEnumerable) monad-related stuff?
interface IMonad<T>
{
SelectMany/Bind();
Return/Unit();
}
That would allow to write functions that operate on any monadic type. Or it's not so critical?
... with all those new (and not so new if we count IEnumerable) monad-related stuff?
interface IMonad<T>
{
SelectMany/Bind();
Return/Unit();
}
That would allow to write functions that operate on any monadic type. Or it's not so critical?
Here is an article by Wes Dyer talking about the use of Monads in C#.
http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx
Is there anyone besides you who wants to write a method that operates on all monadic types? If not, then that's not a whole lot of impetus for the BCL guys to go to all the trouble of designing, implementing, testing and shipping such an interface, not to mention making sure that it is implemented on every possible monadic type.
I'm having a hard time thinking of a function that I would want to write that could take any monad. Can you give me an example of such a function?
Think about what the signature for IMonad<T>
's methods would have to be. In Haskell the Monad typeclass is defined as
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
It's tricky to translate this directly to a C# interface because you need to be able to reference the specific implementing subtype ("m a" or ISpecificMonad<a>
) within the definition of the general IMonad interface. OK, instead of trying to have (for example) IEnumerable<T>
implement IMonad<T>
directly, we'll try factoring the IMonad implementation out into a separate object which can be passed, along with the specific monad type instance, to whatever needs to treat it as a monad (this is "dictionary-passing style"). This will be IMonad<TMonad>
and TMonad here will be not the T in IEnumerable<T>
, but IEnumerable<T>
itself. But wait -- this can't work either, because the signature of Return<T>
for example has to get us from any type T to a TMonad<T>
, for any TMonad<>
. IMonad would have to be defined as something like
interface IMonad<TMonad<>> {
TMonad<T> Unit<T>(T x);
TMonad<U> SelectMany<T, U>(TMonad<T> x, Func<T, TMonad<U>> f);
}
using a hypothetical C# feature that would allow us to use type constructors (like TMonad<>) as generic type parameters. But of course C# does not have this feature (higher-kinded polymorphism). You can reify type constructors at runtime (typeof(IEnumerable<>)
) but can't refer to them in type signatures without giving them parameters. So besides the -100 points thing, implementing this "properly" would require not just adding another ordinary interface definition, but deep additions to the type system.
That's why the ability to have query comprehensions over your own types is kind of hacked on (they just "magically" work if the right magic method names with the right signatures are there) instead of using the interface mechanism etc.
Monads simply aren't important to .NET programmers. Without even knowing monads exist you can still build the LINQ framework. More importantly, it wouldn't look any different. It doesn't matter if you think in terms of monads (Haskell), expression tree rewriting (Lisp), set-based operations (SQL), or using map/reduce to create new types (Ruby, Python), the end result is going to be the same.
In fact, I would go so far as to say that monads are downright useless to .NET developers. Every time I see a library for .NET based on monads, it is invariably both more verbose and less comprehensible than straight C# or VB code. The reason is simple, languages like C# and VB are built on much, much more powerful building blocks than languages like Haskell.
Haskell in particular needs to use monads for everything because that is all they have. The same goes for macros in Lisp or dynamic typing in JavaScript. When you have a one-trick pony, that trick has to be pretty damn good.