To expound on this connection: the basic idea is that a Promise has a `.then(fn)` method call which takes this `fn`, which returns a value. If that value is not a Promise, then it is lifted to a new promise; either way that promise is what's returned by the .then().
In Haskell, for type safety, you have to explicitly write this conversion and the function which does it has the somewhat-confusing name `return`. The `.then()` method then has the name `>>=`, pronounced "bind".
If you have these, you have a template for type-safe functional metaprogramming. Given any x, you can produce "a program which produces an x" (return), and given any function from an x to a program which produces a y, you can bind that onto a program which produces an x, to produce a program which produces a y:
return :: x -> ProgramWhichProduces x
(>>=) :: ProgramWhichProduces x -> (x -> ProgramWhichProduces y) -> ProgramWhichProduces y
This was huge historically because you can still metaprogram in a purely functional language, even though you cannot do things which have side-effects. So I can give you a pure primitive like `println :: String -> ProgramWhichProduces Nothing` and you can build `println("Hello, world!")` with it, and there are no side-effects in running that function on that input, so this is purely functional. In this way the act of actually running a `ProgramWhichProduces x` as an executable is deferred until the language is no longer in play: when the compiler is run, it looks for a `ProgramWhichProduces Nothing` called `main` and writes that out as the actual executable generated by the compiler.
Monad refers then to precisely this design pattern of saying "I have some trivial embedding `x -> m x` into my problem domain `m` and I have some way to combine an `m x` with an `x -> m y` to produce an `m y`, hey, that's a monad!" ... One example is list comprehensions; there is a trivial way to embed any element as a singleton list [x] and then you can always use any function x -> [y] (called a "transducer" in Clojure) to process a list [x], concatenating together all of the [y]'s you get along the way. With ES6 generators this looks like:
function* forEach(iterator_x, ys_from_x) {
for (let x of iterator_x) {
yield* ys_from_x(x);
}
}
Hey, that's a monad. You can write a list comprehension like:
// equivalent to Python's [f(x, y) for x of list_x for y of list_y if predicate(x, y)]
forEach(list_x, x => forEach(list_y, y => predicate(x,y) ? [f(x, y)] : []))
In Haskell you can write all monads with a special syntax called `do`-notation; you can write the above in any of three ways:
[f x y | x <- list_x, y <- list_y, predicate x y]
-- which desugars to...
do
x <- list_x
y <- list_y
if predicate x y then [undefined] else []
return (f x y)
-- which desugars to almost exactly the JS above...
list_x >>= \x ->
list_y >>= \y ->
(if predicate x y then [undefined] else []) >>= \_ ->
return (f x y)
So that's the general pattern of monads and do-notation in a short, sweet lesson.
In Haskell, for type safety, you have to explicitly write this conversion and the function which does it has the somewhat-confusing name `return`. The `.then()` method then has the name `>>=`, pronounced "bind".
If you have these, you have a template for type-safe functional metaprogramming. Given any x, you can produce "a program which produces an x" (return), and given any function from an x to a program which produces a y, you can bind that onto a program which produces an x, to produce a program which produces a y:
This was huge historically because you can still metaprogram in a purely functional language, even though you cannot do things which have side-effects. So I can give you a pure primitive like `println :: String -> ProgramWhichProduces Nothing` and you can build `println("Hello, world!")` with it, and there are no side-effects in running that function on that input, so this is purely functional. In this way the act of actually running a `ProgramWhichProduces x` as an executable is deferred until the language is no longer in play: when the compiler is run, it looks for a `ProgramWhichProduces Nothing` called `main` and writes that out as the actual executable generated by the compiler.Monad refers then to precisely this design pattern of saying "I have some trivial embedding `x -> m x` into my problem domain `m` and I have some way to combine an `m x` with an `x -> m y` to produce an `m y`, hey, that's a monad!" ... One example is list comprehensions; there is a trivial way to embed any element as a singleton list [x] and then you can always use any function x -> [y] (called a "transducer" in Clojure) to process a list [x], concatenating together all of the [y]'s you get along the way. With ES6 generators this looks like:
Hey, that's a monad. You can write a list comprehension like: In Haskell you can write all monads with a special syntax called `do`-notation; you can write the above in any of three ways: So that's the general pattern of monads and do-notation in a short, sweet lesson.