A Challenge Problem for Promise Designers
Tab Atkins Jr.
jackalmage at gmail.com
Sat Apr 27 09:28:00 PDT 2013
On Sat, Apr 27, 2013 at 7:38 AM, Mark Miller <erights at gmail.com> wrote:
> On Fri, Apr 26, 2013 at 1:51 PM, Tab Atkins Jr. <jackalmage at gmail.com>
>> On Fri, Apr 26, 2013 at 1:45 PM, Domenic Denicola
>> <domenic at domenicdenicola.com> wrote:
>> > From: Tab Atkins Jr. [jackalmage at gmail.com]
>> >> Shorter me: this is why I keep asking people who want flattening to
>> >> actually provide an example of where flattening is useful, that isn't (a)
>> >> assimilation, (b) a result of weird language semantics from some non-JS
>> >> language, or (c) an authoring error.
>> > Since (multi-level) flattening only occurs for assimilation (per
>> > Promises/A+ 1.1), it appears we have been talking past each other. All
>> > examples of multi-level flattening will necessarily be examples of
>> > assimilation.
>> In that case, HUZZAH! We've solved the problem!
> We may have.
> When I argue for default flattening (#0 in my "What Are We Arguing About")
> and you argue against, you claim default flattening is not monadic, which I
> agree with. But then you go on to explain as "monadic" a semantics that
> seems like default flattening to me. I am curious if you could define what
> you mean by "monadic". I don't much care if we call a promise system
> "monadic" or not, but let's not let a disagreement on this term obscure a
> possible agreement on what promises should do.
Hmm, that's strange. I just mean "following the monad laws". In
other words, Promises are monads, with .then as the monadic operation,
taking a function of type "a -> Promise<b>", and resulting in a new
Promise. (For convenience, .then() is also the functor operation,
allowing its function to be of type "a -> b", as long as "b" isn't a
Promise. But that doesn't harm the monad-ness, as long as you follow
the laws.) Future.accept (or its equivalent in a final Promise spec)
is the monadic lift operation.
We don't expose it explicitly (though we could), but the monadic
"join" operation takes a Promise<Promise<a>>, and returns a new
promise that waits for both the inner and outer to accept, then
accepts with the inner's state. If either rejects, the output promise
rejects with the same reason.
Did you think I meant something else? If so, what? And, do you think
I've made a mistake in describing the monadic properties of promises?
If so, what?
> As I made clear in my "What Are We Arguing About" email, I want to separate
> the argument about default flattening (#0) from the argument about whether
> promises-for-promises are possible (#1), and from arguments about thenables
> and assimilation (#2,#3,#4).
> AFAICT, leaving aside operations that would explicitly create
> promises-for-promises, i.e., "fulfill" (aka "accept"), I don't see how it is
> possible to create promises-for-promises with the remaining operations you
> and I seem to agree on: Q(x) (aka "Future.resolve(x)"), "then", "resolve",
> "reject". If promise-for-promises cannot be made in the first place, then no
> recursive unwrapping is required to take them apart. Specifically,
> assimilation aside and API details aside, what about Q do you disagree with,
> if anything?
Correct - if you leave out the only promise constructor that can
actually make promises-for-promises, you can't make
promises-for-promises. ^_^ Thus, recursive unwrapping, outside of
the assimilation use-case, isn't useful, as it's very hard to nest
promises unless you're doing it on purpose. (And if you are doing it
on purpose, it's potentially useful to have it act monadic.)
> If we can narrow our remaining disagreements down to #1..#7, that would be
> great progress. Yes, #1..#7 will still be a lot of work, but great progress
> nonetheless. And I will leave to you and other to fight about what is and
> isn't called "monadic" ;).
No fights necessary, luckily - the monad laws are completely trivial,
and it's easy to prove something does or doesn't obey them.
More information about the es-discuss