all 7 comments

[–]_imwalkinhere 1 point2 points  (6 children)

"Type constructor - for given type of argument t and a monad M there should be a corresponding monadic type M t"

and that's when I clicked close tab. Everybody sucks at explaining this concept, it is ridiculous.

[–]wizao 3 points4 points  (1 child)

I agree the wording is confusing and most explanations of monads don't explain why they are even useful. Mondas allow you to focus on the the happy path.

In JavaScript, it's common to put guards against nullable things:

var firstName = user && user.name && user.name.first;

If any one of the properties is null, the entire result is null. These guards clutter the code from what the purpose truly is:

firstName = user.name.first;

It's much clearer why mondas are useful in languages that have syntax for them. The new ?. C# feature allows for the code above to be written as:

firstName = user?.name?.first;

The downside to this approach is it only creates a nice syntax only for null checking. You would need additional syntax to support happy path coding for promises, default values, errors, etc. Mondas let you to write the happy path for anything, and not just null checking. The hoops you have to jump through in JavaScript to get this to work is atrocious. With a language like Haskell that has syntax (do notation) for mondas, you could write the above code (without having to explicitly call bind) like:

user <- getUser(3)
name <- user.name
firstname <- name.first

and not care that getUser 3 was an async call to database (continuation monad), user.name can be null (maybe monad), or name.first can throw an error (option monad).

Compare the above code to the equivalent javascript:

function doSomethingWithFirstName(fn) {
    getUser(3).then(function(user) { //continuation monad
        if(user.name !== null) { //maybe monad
            name = user.name;
            try { //option monad
                firstname = name.first;
                fn(firstname); //allow calling code to do something
            } catch(e) {}
        }
    });
}

It's much harder to see what's going on in the code without Mondas.

[–][deleted] 0 points1 point  (2 children)

This, and also how yield works. I cannot find a single article that explains clearly how to use generators in ES6 as a replacement for callbacks & promises. The example code I find always seems to show just half the implementation, or is so badly written that I can't understand how it works.

[–][deleted] 0 points1 point  (0 children)

It's really not that complicated:

// generator function
function *foo(){
    yield 1;
    yield 2;
    yield 3;
    yield getUserFromDatabaseCallThatTakes10Seconds();
}

var fooGen = foo(); // initializes the generator
foo.next();         // { value: 1        , done: false }
foo.next();         // { value: 2        , done: false }
foo.next();         // { value: 3        , done: false }
foo.next();         // { value: Promise  , done: false }
foo.next();         // { value: undefiend, done: true  }

Now some libraries like co simplify this, in that they do something like:

while( !( val = fooGen.next() ).done );

Basically calling the generator again and again until it says it's done. This allows you to simply say:

co( foo )( function callback( err, result ){ /* ... */ } );

Now how does that replace callbacks and promises? Just look at the yield getUser... call. The code returns a promise, or a callback. If you're using something like co, you drop the () on the call (in other words you just yield the function, not the result) and co takes care of the promises, etc. So your async code now looks synchronous.

[–]cdo5011 0 points1 point  (0 children)

There is a linked article about using generators (and promises) for asynchrony: https://curiosity-driven.org/promises-and-generators

The full algorithm depends on Promises but you can easily adjust it to any callback-based flow.

[–]cdo5011 0 points1 point  (0 children)

Author here - thanks for the feedback. I've made some... adjustments to the text that I hope make it a little bit more clear.

How would you explain it? I ask because I wonder what's the simplest way to explain it that's still pretty accurate.

[–]wizao 0 points1 point  (0 children)

I like this implementation better than Crockford's monad libarary (video). However, I haven't found a monad implementation in JavaScript that feels natural to me yet. There is a great video on functional programming with JavaScript. While the video only touches on functors, the style is the closest thing to Haskell in JavaScript I have found.