On Jun 17, 2010, at 10:47 AM, caseyh@istar.ca wrote:

The functional-object style seems to be gaining momentum.
Is there any way to convert monads into objects, so that beginners have an easier time with the syntax and thus we can attract more people to the language?

I think you're a little bit confused about monads.  When you define a monad instance, all you are doing is defining the syntax that lets you chain properly typed computations together.  (>>=) does almost exactly what (->) does in object oriented Perl, and what (.) does in Ruby and Java.  

Consider something like:

1.plus(10).minus(5).square.log
return 1 >>= return . (+10) >>= return . (-5) >>= return . square >>= return . log

They both bind the "return value" of a computation (or chain of computations) to the next function in the chain.  return kind of does the opposite.  It takes a value that can be "in" the monadic action/object and gives/returns a monadic action/object that contains it. 

So what are the differences between the two examples?  First, and most obvious, Haskell's is a bit more verbose, because it explicitly uses return to set the right context, whereas the ruby/python/whatever version does it implicitly.  On the other hand, if we can abstract the (return .) function away, with liftM:

return 1 >>= liftM (+10) >>= liftM (-5) >>= liftM square >>= liftM log

Indeed, if we really really want, we can define "methods" for the monadic action, just to make it look like Python/Ruby.  (Actually, this is probably the preferred way to build up complex computations, though it is kind of silly to do for the arithmetic operators)

plusM :: (Monad m, Num n) => n -> m n
plusM n = liftM (+n)
...
squareM :: (Monad m, Num n) => n -> m n
squareM = liftM (^2)

logM :: (Monad m, Num n) => n -> m n   -- for exposition, I am assuming log is a part of the Num typeclass.  
logM = liftM (log) -- I guess it's really in Rational

Suddenly, we have something that looks a LOT like the object oriented version:

return 1 >>= plusM 10 >>= minusM 5 >>= squareM >>= logM

In fact, this is (almost) exactly like how Perl defines its object methods.  The first argument of any function/procedure is assumed to be the object on which the method acts, and the dereferencing operator (->) "knows" to bind the last returned value to the first free variable.  The difference is that Perl objects "know" to which class they belong, so they can resolve compile time ambiguity at runtime (if the program is properly typed, which Perl can't validate at "compile time"...).  Since 1 is a literal in Perl, we would have to make a Number class and instantiate a Number object to get this to run:

Package Number;
sub new { my $class = shift; my $self = shift; bless $self, $class; return $self;
sub plus arg { return $self + arg; }
sub minus arg { return $self - arg }
...

so that the computation we have been comparing turns out as:

(new Number 1) -> plus 10 -> minus 5 -> square -> log;

Indeed, we are "stuck" in the number class, and (in principle) can't get out without a properly typed function.   (It's also kind of interesting that the constructor method literally includes the snippet "return $self", which is almost equivalent to return 1, when you bind 1 to (new Number).  That is, the Number constructor takes a "regular" value and turns it into a Number, just as return takes a value and wraps it in a monadic type.  

The difference is that 1 isn't "blessed" into the Number class if you just do

return 1 -> plus 10 -> minus 5 -> square -> log

in Perl, so the dereferencing operator (->) will fail.  You need the "bless $self, $class" machinery that the constructor runs.  In comparison, Haskell's return operator polymorphically "blesses" into any monadic type, in virtue of its type signature return :: (Monad m) => a -> m a), so that the bind operator (>>=) will never fail.

The thing that makes object orientation special isn't the syntax.  It's the relationship objects and classes have to one another -- and how classes relate to each other.  Depending on your perspective, there is a unique largest or smallest class to which an object belongs.  That relationship is a monadic adjunction.  So, in particular, you can make a type-unsafe object system in Haskell by relating a "class" (for example: a named list of methods) to a type or value.  If you want type safety, you need to use type arithmetic to implement this monadic adjunction at compile time.  Somebody else mentioned OO Haskell.

Finally, if you want to put this all very abstractly, but in nice common language, an object and its corresponding monadic action are both "servers".  Bind, dereferencing, etc are the interfaces that can make a request from "ANY" server.  So the State Monad is a server that serves/changes the current state.  The list monad is the server that serves up each element of a list, in turn, etc.  Erlang ran with this idea for their "distributed functional object system".