FWIW, I'm actually not that thrilled about this sort of deferred approach. In Rx, that is part of the reason 'hot' vs 'cold' documentation has to exist, and I've seen many people struggle with it in theory & practice.
A lot of tough calls had to be made and pragmatic best interest of users typically triumphed over purity.
A promise is monadic if you drop exceptions and use the `then` overload which is `bind`. You have a `pure` - `resolve`.
The promise constructor has to exist to interop with callbacks but for no other reason really.
It became a pain point for me when using Promises as part of a larger abstraction, where the exact use was not known. Then I've worked around the strictness by embedding a "trigger" into a set of Promises so that I can set them off all at once, after they are all created.
Good article, btw. One of these days the Monad/Category lightbulb is going to go off for me, and this brought me closer to that using a familiar example.
Basically the counter-argument is that promises are not composable, i.e. you can't wrap a promise in another promise.
There was an attempt to convince the spec authors to make promises "true" monads but it failed for reasons of simple practicality: https://github.com/promises-aplus/promises-spec/issues/94
However the hot/cold distinction in Rx is because execution is not deferred, as I understand it. IIUC observables / streams / whatever they are called in Rx start running as soon as they are defined. If `naturalNumbers` is the event stream of natural numbers, the result of
naturalNumbers.map(x => print(x))
might not output 0, 1, ..., because a whole bunch of natural numbers might have already been emitted before `map` is called. It is this difficulty with reasoning that motivates hold/cold streams (again, as I understand it). A simple solution is to separate defining the network and running it. e.g. by requiring calling `run` method to get a result. Then substitution is maintained in the "world" prior to calling `run`, and this distinction is unnecessary.The complications to this that make for so much documentation come from the places where those "mostly" answers are wrong: Rx has ways to build hot Observables that are not deferred and begin immediately; Rx has a few rare exception Operators that can force an Observable hot, those confusing matters; finally, Rx cold Observables by default don't share deferred execution so multiple subscriptions create multiple "heat transition" side effects (ie, an observable is "run" every time it is subscribed). There are mechanics and operators in place to deal with all of these cases in Rx, but that adds to the learning curve of knowing when deferred execution takes place. (So yes the separation you describe exists between creating a network of cold observable and making them all "hot", but it does bring its own complications only furthering the need for the hot/cold distinction in cases where you are trying to avoid repeating things like side effects, which will happen when you aren't properly sharing the same "hot" source.)
So yes, Hot/Cold is entirely about deferred versus immediate observables/streams and both the surprises of finding a hot observable when you expected a cold one (as in the case of your example) or even a cold observable when you expected a hot one (side effects and memory leaks and "no execution" problems because you forgot to make anything hot).
E.g. `map(x => x*2, [1, 2, 3])` (no need to write `R.map`)
I'm not sure that .bindTo() chaining reads any better than .then() chaining or async.waterfall().
I think the final example (of myLongOperation) reads extremely well, and is pretty minimal, as the author states.
I agree that bindTo is not much different from then, but IMHO pipe and pipeTo are.
class Callback
.....
this.then = g => new Callback(callback =>
Can't we just keep OOP out of FP?
Does something like that exist?
If not maybe I should try Kleislis instead. But I'd like my code to be accessible for my colleagues. And it's my rule of thumb that I try not to use point free constructions (like Kleislis) because a lot of colleagues will no longer understand my code easily.
Personally I don't use promises and won't use this either but that's only because I am working on a code base that needs to work in more places (so no ES6 for me and no I don't need the extra complexity in my build and debugging steps to do a transpile).