I have no idea why both you and Brendan assert that I was arguing/
rehashing for deep delimited continuations (let alone call/cc).
Because you wrote:
"1 can be worked around, but not with the usual tools of function
definitions and calls - "yield" forces use of "function*" and "yield*"
for abstracting over expressions containing it."
and later:
"For instance, we cannot write
function* g() { (function(){ yield 1 })() }
This certainly looks like you want a deep continuation.
Ah, thanks, that explains it. Yes, I was listing examples that trouble
me about the current design, I was suggesting changes to that
design, and some of the examples could only be solved by deeper
continuations.
The point of departure is that my suggested changes wouldn't actually
solve all the cases that trouble me (in particular, not those cases that
would depend on deep continuations). Issues that I've tried to address
include:
1. the example above doesn't require "deep" continuation any more
than local variable declarations in a generator require them.
Let me change the example to use immediately applied arrow
functions (to avoid any special once-per-function-body handling
of "this" and "arguments"); then I would expect
function* g() { (()=>{ let x = 1; yield x })() }
to be equivalent to
function* g() { { let x = 1; yield x } }
and if the latter is considered valid/shallow, I would expect the former
to be valid/shallow, too.
2. I'd like to decouple generators from "function", to avoid interference
between the two features.
For concreteness, let me assume a block form of generators as
"do* { ... }" (delimiting continuations to the block, giving a generator-
valued expression). Then the example would read (ignoring item 1
above for now, so we have to use "yield*"):
var g = () => do* { yield* (()=> do* { yield 1 } )() }
With "function", this would be slightly longer than with the current
spec, but since generators are now decoupled from "function", we
can use (arrow) functions (our means of functional abstraction) freely -
generators are simply another class of object to write functions over.
We could even re-introduce
function* f() { ... }
as mere syntactic sugar for
function f() { return do* { ... } }
3. I'd like to see a standard iterator library, with things like zip and
feed (the exact contents of such a library would evolve in practice,
not from a spec, but the spec could provide a seed, and organize
the evolution), and I would like to see more support for composing
generators.
Using the current spec, we could define
function* then(g1,g2) { yield* g1; yield* g2 }
and use this to combine generators via ES5 array iterations
[1,2,3].map(function*(x) { yield x }).reduce(then)
or, assuming item 2 above,
function then(g1,g2) { return do* { yield* g1; yield* g2 } }
[1,2,3].map(x=>do* { yield x }).reduce(then)
This, as well as my generators-as-monads gist, suggest that we
could let generators return their completion value and have them
implement monadic .then, for easy composition using the monadic
set of tools.
And since "yield*" is essentially a mini-interpreter built on top of
"yield", the composition library could include alternative interpreters
(eg, support for early return).
So, none of my suggestions require deep continuations. Nevertheless,
I'm having trouble distinguishing local blocks in shallow-continuation
generators from deep-continuation generators. So I'd be interested to
hear the precise arguments against deep delimited continuations (link
to meeting notes/mailing list thread would be fine).
Claus
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss