
Monads for Java/C++ programmers - kunley
http://irekjozwiak.com/entry/2009/06/13/Monads-for-Java-C---programmers.html
======
d0m
Ok well, in my free time, I was reading learnyouahaskell.com (Which, by the
way, is pretty great but a bit slow-ish if you aren't new in the functional
way of thinking).

And I was kind of anticipating monads since I keep hearing that they just blow
your mind and are hard to understand. So, I was happy to read this article and
found it quite good actually :) Good job to the author.

Here's how I can summarize it: monads are a kind of pattern which "implements"
">>=" and "return" as a Int implements "eq" or "ord". The job of >>= is to act
a little bit like the Null Pointer pattern in the OO world. For instance, if
everything is ok, it returns the good value else it throws an exception or
return an error value. However, to use the >>= function, you need to
encapsulate your first value. Depending of monads, that "encapsulated" value
may be different. In this article, we were working with the Maybe type,
however, monads can be of any type. So, the "return" function takes care of
encapsulating the value in the right type so that the >>= function can use it.

Anyhow, that's what I understood ;-) And I'll continue to read
learnyouhaskell.com

------
eplanit
I don't know, I read all these painful explanations of what monads
are...combined with more stretches of the imagination to explain plausible
uses for them. In the end, the authors achieve neither, with me.

I tend to write these off with "yeah, in my 20s and early 30s whilst in
graduate Comp. Sci. schooling I enjoyed all this esoteric crap, too". :-)

~~~
shrughes
This is mostly because the monad abstraction is mostly useless in non-lazy
languages. It's more useful in lazy languages because objects with monadic
types can then be written self-referentially without trouble. It also hurts
that Java and C++ syntax is extremely specialized towards avoiding the use of
abstractions.

~~~
fauigerzigerk
C++ may be overly complex but it is in an entirely different league than Java
in terms of syntactical abstractions that you can implement on top of it.

~~~
shrughes
That's true. But there's still a syntactic cost and a cognitive cost to making
useful abstractions that can be much less verbosely and more comfortably made
in other languages. And I find myself going with less clean designs because of
it.

~~~
fauigerzigerk
I agree with that.

------
tumult
Pft, dude whatever. This is HN. We don't want lame-o languages like Java, or
boring monads like Maybe. We want crazy languages like JavaScript, and the
mother of all monads, the continuation monad. Here's an equivalent to what's
posted in this article, but more powerful, and in JavaScript:

    
    
        // Haskell typeclass equivalent is >>=
        // which has a signature of:
        // m a -> (a -> m b) -> m b
        // which in our case, is the more specific:
        // Cont a b -> (b -> Cont a c) -> Cont a c
        function bind(x, y) {
            return function(k, end) {
                return x(function(result) { return y(result)(k, end); }, end);
            }
        }
        
        // 'yes' can also serve as identity for this monad. Haskell monad typeclass
        // equivalent is 'return', not to be confused with JavaScript return. if
        // this were an applicative functor, we would call it 'pure' instead, even
        // though it does the same thing.
        // b -> Cont a b
        function yes(x) {
            return function(k, end) { return k(x); };
        }
        
        // bail out.
        // a -> Cont a b
        function no(x) {
            return function(k, end) { return end(x); };
        }
        
        // look up a user ID from a name string, in the context of a continuation
        // monad. our type signature for this in Haskell would be:
        // String -> Cont String UserId
        // or something.
        // 'UserId' would be a newtype wrapper around Integer, to prevent
        // accidentally conflating it with account balance or another numeric type.
        function userid_from_name(person_name) {
            switch (person_name) {
                case "Irek": return yes(1); // we have three user names in our system
                case "John": return yes(2);
                case "Alex": return yes(3);
                case "Nick": return yes(1); // Nick is on the same acct as Irek
                default: return no("No account associated with name " + person_name);
            }
        }
        
        // UserId -> Cont String Balance
        // 'Balance' would also be a wrapper around Integer type
        function balance_from_userid(userid) {
            switch (userid) {
                case 1: return yes(1000000); // some amounts for a couple of accounts
                case 2: return yes(75000);
                default: return no("No balance associated with account #" + userid);
            }
        }
        
        // Balance -> Cont String Balance
        // we could do something fancier here if we liked, like pass the difference
        // between the minimum required balance for a loan and the actual balance.
        function balance_qualifies_for_loan(balance) {
            if (balance > 200000) return yes(balance);
            else return no("Insufficient funds for loan, current balance is " + balance);
        }
        
        // tada. put it all together.
        // String -> String
        function name_qualifies_for_loan(person_name) {
            return bind(bind(userid_from_name(person_name), balance_from_userid),
                        balance_qualifies_for_loan)(
                function(x) { return "This person qualifies for a loan. Their \
                                      account has a balance of: " + x; },
                function(x) { return "Do not issue loan, reason given: " + x; }
            );
        }
    

Test some output:

    
    
        > name_qualifies_for_loan("Irek");
        "This person qualifies for a loan. Their account has a balance of:
        1000000"
    
        > name_qualifies_for_loan("John");
        "Do not issue loan, reason given: Insufficient funds for loan, current
        balance is 75000"
    
        > name_qualifies_for_loan("Alex");
        "Do not issue loan, reason given: No balance associated with account #3"
    
        > name_qualifies_for_loan("Nick");
        "This person qualifies for a loan. Their account has a balance of:
        1000000"
    
        > name_qualifies_for_loan("Foo");
        "Do not issue loan, reason given: No account associated with name Foo"
    
    

Pure functional. Holler at a player.

~~~
viraptor
This example actually looks a bit contrived... If your language supports
exceptions, but doesn't support nice syntax for monads (i.e. you still have to
write all the levels with bind and parentheses), why not simply throw() on
error? I guess you would normally write something to support function like
_bindl(person_name, [userid_from_name, balance_from_userid,
balance_qualifies_for_loan])_ anyways... but that's still not that nice.

The call becomes simpler:
_balance_qualifies_for_loan(balance_from_userid(userid_from_name(person_name)))_
, as well as functions which just return the value or throw.

~~~
tumult
You are critiquing this as if I were suggesting people use it in production
JavaScript code, which I'm not. It's a demonstration. Did you read the
original article? It has an example that's even more contrived (and also
incomplete.) You aren't even pointing out the biggest reason not to use monads
in JavaScript (no hints, sorry!)

I'm going to go eat a burrito now.

~~~
viraptor
Ok - I guess I deserved a big WHOOOOSH. I actually thought you were being
serious.

~~~
tumult
All good :)

Implementing exceptions with the continuation monad is straightforward. As you
can see, that's sort of how it's used here. You can also recreate the State
monad, Maybe, and others, deriving each from the continuation monad. I don't
recommend this for actual use in JS, because JS lacks tail call optimization,
which means any serious use of monads will cause stack overflows straight
away.

But it gets crazier: you can implement the continuation monad using JavaScript
exceptions. And JavaScript exceptions _do_ cause the stack to reset (with a
performance penalty). So if you derive a continuation monad in JS from its
built-in exceptions mechanism, you can implement the other monads without
breaking the stack.

~~~
nostrademons
You can also implement them with a setTimeout(0), which gives the browser's
event loop a chance to run so that you don't lock up the browser forever. I
did something like this with ArcLite, resetting the stack with a setTimeout(0)
after ever top-level definition was parsed, so that it didn't take 30 seconds
of unresponsive browser for the standard library to load. It occurred to me
afterwards that I could've used this to implement continuations, but by then I
was pretty much done with Arc development.

~~~
tumult
This has actually been done, in Inria's HOP project with Scheme->JS

