A simple introduction to why Monads are useful

On occasion, I will reference similarities between the JavaScript example and its counterparts in the programming language Haskell. I do this only because most formal literature on monads references Haskell, and it helps to become familiar with the language. Feel free to skip these parts if you prefer.
Maybe We Have a Problem
After the Identity monad, the Maybe monad is perhaps one of the simplest examples of a monad available. It's also quite useful.
The Maybe monad provides an elegant solution to the common problem of multiple nested null checks in code. Consider the following trivial example:
var person = {
     (return x) >>= f = f x
          return value;
       console.log(state);
    }
    };
  };
  if (typeof value === 'undefined' || value === null)
    return fn.call(this, value);
        =   m
m0 + m     console.log("State unknown");
    }
}
So far, all we have done is replace a null check with a check for Nothing. This is not quite what we want.
Maybe We Need Composition
One of the defining characteristics of a monad is that it may be combined with other monads of the same type. That is, we should be able to sequence two I/O operations together. In Haskell, this is written as an infix operator >>, so that putStrLn "abc" >> putStrLn "def" is an I/O action that returns a value of type a. The return operation takes a value from a plain type and puts it into a container using the constructor, creating a monadic value: M a.
    The unary return operation takes a value from a plain type and puts it into a monadic container of type M a; the bind operation chains a monadic value of type M a with a function of type a  M b to create a monadic value of type M b.
Monad laws
For a monad to behave correctly, the definitions must obey a few axioms, together called the monad laws.[11] The = symbol indicates equivalence between two Haskell expressions in the following text.
    return >=> g = g
    f >=> return = f
    (f >=> g) >=> h = f >=> (g >=> h)
fmap and join
Although Haskell defines monads in terms of the return and bind functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type (tu )  M  tM u,[12] takes a function between two types and produces a function that does the "same thing" to values in the monad. The join operation, with type M (M t)M t, "flattens" two layers of monadic information into one.
The two formulations are related as follows:
fmap f m = m >>= (return . f)
join n = n >>= id
m >>= g   =   m
m0 + m      Finally, the monad-related structure is reassembled over all of the results, giving a single value of type (M u).
Given a type constructor M, in most contexts, a value of type a.
We can think of a value of type a; the operand on the left is an I/O action that prints two lines of text to the console. The type of >> is IO a  IO b  IO b, meaning that the operator takes two I/O operations and returns a third that sequences the two together and returns the value of the function application. Since Nothing has no value, anything bound to a Nothing should simply return Nothing (our short-circuit).
Maybe = function(value) {
  var Nothing = {};
  var Something = function(value) { 
    A binding operation of polymorphic type (M t)?(tM u)?(M u), which Haskell represents by the infix operator >>=. Its first argument is a value in a monadic type, its second argument is a function that maps from the underlying type of the first argument to another monadic type, and its result is in that other monadic type. Typically, the binding operation can be understood as having four stages:
     The unary return operation takes a value from a plain type and puts it into a container using the constructor, creating a monadic value: M a.
    The given function is applied to all of those values to obtain values of type (M u).
         return def;
    }
    do { m } = do { v < return x; f v }
    else {
     return Maybe(fn.call(this, value));
        bind: function(fn) { return this; }
  };
  var Something = function(value) { 
         return Nothing;
  return Something(value);
};
Now we have a function Maybe (in monadic terms, our unit function) that returns an object Nothing if the value provided to it is null or undefined and returns a function Something that returns the original value if the value is not null or undefined. (For clarity, I've renamed Haskell's Just with Something, as I find this terminology a bit easier to follow when first being introduced to the concept.)
What can we do with the above? Let's try it out:
Maybe(null) == Nothing; // true
typeof Maybe(null); // 'object'
Maybe('foo') == Nothing; // false
Maybe('foo')(); // 'foo'
typeof Maybe('foo'); // 'function'
So now we've put all of our != null checks into a single function, which is the constructor for the new Maybe type. But is this enough to solve our problem? Unfortunately, no. Let's try it out:
if (Maybe(person) != Nothing && 
  Maybe(person["address"]) != Nothing) 
{
    var state = person["address"]["state"];
    if (y = 0) 
    return true; 
    
           return def;
    }
  };
  var Something = function(value) { 
    return fn.call(this, value);
           The monad-related structure on those values is also pierced, exposing values of type u.
        isNothing: function() { 
    
        console.log("State unknown");
    }
}
All those null checks are fairly ugly. They're tedious to write and annoying to read, an unfortunate side-effect of working in a language in which null was implemented rather poorly. Is there perhaps a way to factor them out? Yes there is.
Maybe We Have a Solution
What we want is to embed the computation of != null into a function or type or class that we can easily re-use so that we don't have to spatter our code with null checks. This is exactly what the Maybe monad provides. In Haskell, the definition of type Maybe is rather succinct:
data Maybe t = Just t | Nothing
All this means is that an object of type Maybe either has some value (Just t) or no value (Nothing). What is meant by Nothing depends on the context. In JavaScript the only things that mean "nothing" are null and undefined. But as you will see, with the Maybe monad, we can change the semantics of "nothing" to suit our needs.
We can begin to model the Haskell definition in JavaScript as follows:
Maybe = function(value) {
  var Nothing = {
        return function() {
     isNothing: function() { 
    let! x = readNum()
    let! x = readNum()
    let! x = readNum()
    let! x = readNum()
    let! x = readNum()
    let! y = readNum()
    let! y = readNum()
    let! x = readNum()
    let! y = readNum()
    let! x = readNum()
    let! y = readNum()
    let! x = readNum()
    let! y = readNum()
    let! x = readNum()
    let! x = readNum()
    let! x = readNum()
    if (y = 0) 
    then None
    else return (x / y)
  }