Promises are really Monads for asynchronous results.
A Monad kind of wraps a certain value. For example, we might have a Promise JSON from an API call. The bind method of a Monad (>>= in Haskell) takes a JSON Promise, and a function (JSON -> Promise b for some b), and returns a value of type Promise b. Promise.then is equivalent to bind.
In Haskell you might define them like this:
data Promise msg val = Resolve val | Reject msg deriving Show
instance Monad (Promise msg) where
return = Resolve
(>>=) :: Promise msg val -> (val -> Promise msg b) -> Promise msg b
(Reject msg) >>= _ = Reject msg
(Resolve val) >>= f = f val
They would be used like this
newPromise = jsonPromise >>= transformJSON
In JavaScript, you would write
var newPromise = jsonPromise.then(transformJSON)
However, the JavaScript case is slightly different. It is not as strict about types. It is possible (and typical) for transformJSON to return a bare type, rather than a Promise, while Haskell would require a Promise be returned every time. It treats an unwrapped value the same as an already fulfilled promise for that value. But automatically unboxing the promises that are returned gives them the full power of Monads.
No, "automatically unboxing the promises that are returned" does not give Promises "the full power of Monads", because you cannot represent a Promise for a Promise for a value. Promises/A+ breaks parametricity.
I get a _lot_ of mileage out of being able to chain promises like that. If I really need to resolve a promise to a promise, I can resolve to an object wrapping the promise and then unwrap it on the receiving side.
A Monad kind of wraps a certain value. For example, we might have a Promise JSON from an API call. The bind method of a Monad (>>= in Haskell) takes a JSON Promise, and a function (JSON -> Promise b for some b), and returns a value of type Promise b. Promise.then is equivalent to bind.
In Haskell you might define them like this:
They would be used like this In JavaScript, you would write However, the JavaScript case is slightly different. It is not as strict about types. It is possible (and typical) for transformJSON to return a bare type, rather than a Promise, while Haskell would require a Promise be returned every time. It treats an unwrapped value the same as an already fulfilled promise for that value. But automatically unboxing the promises that are returned gives them the full power of Monads.