29

... 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?

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
UserControl
  • 14,766
  • 20
  • 100
  • 187
  • 5
    Eric Lippert explains why some features are not implemented in the framework: http://stackoverflow.com/questions/1331739/enum-type-constraints-in-c/1331811#1331811 – Darin Dimitrov Nov 10 '09 at 18:08

2 Answers2

65

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.

Max Strini
  • 2,288
  • 21
  • 24
  • 10
    Good answer, here's a short version: "it's impossible to define a Monad in C#, the type system isn't powerful enough" :) – Mike Hadlow Jan 14 '11 at 14:26
  • So, maybe in CLR 5.0 or 6.0 or in a post .NET runtime of higher level of abstraction. – Néstor Sánchez A. Jun 30 '11 at 22:12
  • 2
    In my personal opinion, without statically checked side effects (i.e. pure functions) you hit a point of severely diminishing returns in adding more sophistication to the type system rather quickly. The real benefit of a sophisticated type system is being able to establish complex properties/invariants of your program that are proven to hold in all cases (as opposed to being tested to hold for certain cases and heuristically extrapolated from there), but if any function has an extra unrestricted "channel" for input/output that's unchecked by the type system there's not much you can prove. – Max Strini Jan 22 '12 at 00:20
  • @MikeHadlow, I wouldn't say "impossible", rather just cumbersome. You would have to pre-create a multiple inheritance hierarchy (of interfaces of course) to describe--at compile time--the allowable types that can be operated on by each concrete class, with one summarizing interface per IMonad. I'm not sure if this restriction qualifies with Max as defeating the purpose altogether, but personally I think the discipline would be a solid exercise for one's specific domain anyway. I'll let you know how it goes :P – Glenn Slayden Jun 26 '12 at 03:46
  • @MaxStrini, I disagree, I think Monad is a useful abstraction beyond its killer-application in Haskell, the IO monad. Scala has a type system that supports Monads in a non-strict multi-paradigm language, they obviously find it useful. – Mike Hadlow Jun 26 '12 at 16:11
  • @GlennSlayden, As Max demonstrates, you can't define a Monad type in C# as you can in Haskell. I think what you are describing is the current situation in C# that relies on convention, but it means that you can't write higher-kinded polymorphic functions in C# like Haskell's forM or mapM. – Mike Hadlow Jun 26 '12 at 16:15
-20

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.

On LINQ, Monads, and the Blindness of Power

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • 18
    _"The reason is simple, languages like C# and VB are built on much, much more powerful building blocks than languages like Haskell."_ Saying that shows that you have never programmed in Haskell or learnt its concepts fully. – Eric Meadows-Jönsson Jul 01 '11 at 07:25
  • 2
    Deserves downvotes, if only for including a link to "private blog". – Tomek Szpakowicz Jul 01 '11 at 15:29
  • 1
    This does not deserve to be downvoted. The question demands an opinionated view anyway. He gave valid reasons _against_ monads in C#. – usr Jul 01 '11 at 22:01
  • @usr: See. My comment helped. Registration is no longer required to read linked article. – Tomek Szpakowicz Jul 05 '11 at 08:15
  • 4
    This comment is downvoted because it shows a misunderstanding of what a monad is. It's not a style or an interface to program to, or anything else. It is a description of certain properties of a type, *and that is concrete*. It is mathematical truth. It's certainly arguable that *knowing about monads*, or understanding them, is not important to .NET programmers, and it is correct that one need not think in terms of them to do a very large class of things, but the end result is not necessarily the same - and using monads enables composition that is otherwise difficult at best, if not impossible – Matt Enright Jul 29 '11 at 17:58
  • 1
    I always find it funny when people say things like "using monads enables composition". There are numerous articles on things like Monad Transformers to deal with the problem that Monads themselves are not composable. – Jonathan Allen Jul 31 '11 at 01:17
  • 7
    Ah, but I didn't claim that monads were composable. I claimed that using monads enables the composition of certain classes of computations. Monad transformers are the higher-order type constructors that you need to compose monads (by creating a new monad and encoding into it the computations with the properties of both initial monads). – Matt Enright Sep 11 '11 at 20:05