How would shallow generators compose with lambda?

View: New views
6 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 - 4 | Next >

Re: yield syntax (diverging from: How would shallow generators compose with lambda?)

by kevin curtis :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brendan:
> I'm abusing Object as ES5 does, but harder, to avoid polluting the global
> object. I'm supposing Object.implementation could be useful for other
> properties than the supports method. This reads well enough, although its a
> bit long-winded altogether (but individual names are short enough).
> Comments?

Have i got the wrong end of the stick on this...
With ES6 i thought modules would provide some namespace functionality. eg

import meta // or whatever the syntax is
meta.supports("yield")

And a home for any ast functionality:
import ast
let x = ast.parse("3 + 3")

It's interesting that Lua puts its yield/coroutine functionality in a module:
coroutine.yield()

It's function format but at least it's not necessary to worry about
the global namespace (with modules).



On Mon, May 18, 2009 at 8:13 PM, Brendan Eich <brendan@...> wrote:

> On May 18, 2009, at 11:53 AM, Neil Mix wrote:
>
>>> But for this to be true, we would need to use the direct-eval detection
>>> hack I mentioned previously.
>>
>> On the plus side, this would allow for feature detection of generator
>> support, right?  (Is there any other way to detect generator support?)
>
> In JS1.7 you could object-detect:
>
>    if (this.Iterator) ...
>
> or similarly.
>
> But I'm in the midst of writing up strawman:iterators proposal that doesn't
> add Iterator to the global object (nor any __iterator__ getter, no double
> underscores).
>
> One generalized idea for object detection of keywords that could be used as
> if they named functions in code that would be work in old browsers:
>
>    if (Object.implementation && Object.implementation.supports('yield'))) {
>        ...
>        function gen() { ... yield(E); .... }
>        ...
>    } else {
>        ... do something else ...
>    }
>
> I'm abusing Object as ES5 does, but harder, to avoid polluting the global
> object. I'm supposing Object.implementation could be useful for other
> properties than the supports method. This reads well enough, although its a
> bit long-winded altogether (but individual names are short enough).
> Comments?
>
> /be
> _______________________________________________
> es-discuss mailing list
> es-discuss@...
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: How would shallow generators compose with lambda?

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On May 14, 2009, at 2:10 PM, Mark S. Miller wrote:

> On Thu, May 14, 2009 at 1:22 PM, Brendan Eich <brendan@...>  
> wrote:
>> On May 14, 2009, at 12:24 PM, Jason Orendorff wrote:
>>> 3. When a lambda yields, [...]
>>> there may be other functions on the stack, in between. You can't
>>> always statically tell which ones.  This means that generator
>>> semantics affect the integrity of code that isn't in a generator.
>>
>> [...] this extends the finally integrity
>> degradation outside of the lexical scope of the generator function.  
>> Good
>> point.
>>
>>> [...] with generators+lambdas, almost any function call *anywhere*  
>>> in the
>>> program might never return or throw.  This weakens 'finally', at
>>> least.
>> [...]
>
>> function gen(arg) {
>>   foo((lambda (x) yield x), arg);
>> }
>> function foo(callback, arg) {
>>   try {
>>       callback(arg);
>>   } finally {
>>       alert("I'm ok!");
>>   }
>> }
>> g = gen(42);
>> print(g.next()); // tell the user the meaning of life, etc.
>> g = null;
>> gc();
>
>
> Thanks all, this has been very clarifying. You both have put your
> finger on what was nagging at me and explained it clearly.

I think we missed an alternative that comports with Tennent's Oversold  
Correspondence Principle, *and* composes. Thanks to Dave Herman for  
pointing it out.

function gen(x) {
   foo( lambda (x) (yield x*x) );
}

need not yield from gen if the lambda is called from foo or another  
function -- it can throw the same error it would throw if the lambda  
escaped upward/heapward and was called after gen had returned. There's  
no requirement that yield not throw in any case where the lambda is  
not applied in the context of gen.

I've seen magical thinking applied to both TCP and LSP, to the  
detriment of the concrete application of these principles. TCP does  
not mean yield plus lambdas must require delimited continuation.

The big advantage of yield other than the utility (good not great,  
less than some folks want, and hard to compose), and the Python  
brainprint re-use (also good IMHO, but this could degrade over time),  
is the ease of implementation. Ecma TC39 is going to have a hard time  
standardizing deeper continuations. Never mind the challenges facing  
lambda.

/be
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: How would shallow generators compose with lambda?

by Jim Blandy-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 05/28/2009 11:08 AM, Brendan Eich wrote:

> On May 14, 2009, at 2:10 PM, Mark S. Miller wrote:
>
>> On Thu, May 14, 2009 at 1:22 PM, Brendan Eich <brendan@...>
>> wrote:
>>> On May 14, 2009, at 12:24 PM, Jason Orendorff wrote:
>>>> 3. When a lambda yields, [...]
>>>> there may be other functions on the stack, in between. You can't
>>>> always statically tell which ones.  This means that generator
>>>> semantics affect the integrity of code that isn't in a generator.
>>>
>>> [...] this extends the finally integrity
>>> degradation outside of the lexical scope of the generator function.
>>> Good
>>> point.
>>>
>>>> [...] with generators+lambdas, almost any function call *anywhere*
>>>> in the
>>>> program might never return or throw.  This weakens 'finally', at
>>>> least.
>>> [...]
>>
>>> function gen(arg) {
>>>   foo((lambda (x) yield x), arg);
>>> }
>>> function foo(callback, arg) {
>>>   try {
>>>       callback(arg);
>>>   } finally {
>>>       alert("I'm ok!");
>>>   }
>>> }
>>> g = gen(42);
>>> print(g.next()); // tell the user the meaning of life, etc.
>>> g = null;
>>> gc();
>>
>>
>> Thanks all, this has been very clarifying. You both have put your
>> finger on what was nagging at me and explained it clearly.
>
> I think we missed an alternative that comports with Tennent's Oversold
> Correspondence Principle, *and* composes. Thanks to Dave Herman for
> pointing it out.
>
> function gen(x) {
>   foo( lambda (x) (yield x*x) );
> }
>
> need not yield from gen if the lambda is called from foo or another
> function -- it can throw the same error it would throw if the lambda
> escaped upward/heapward and was called after gen had returned. There's
> no requirement that yield not throw in any case where the lambda is
> not applied in the context of gen.
"Not applied in the context of gen" means what, exactly?  Called
directly from gen?  Called only by lambdas enclosed by gen?  Called in
some gen's dynamic scope?

Would yield need to work normally in this case?

function f(x) {
   ((lambda (g, h, x) { return g(g, h, x); })
    (lambda (g, h, x) {
       if (x > 0)
         return g(g, h, x-1);
       else
         return h(x);
     },
     lambda (x) { yield 42; },
     x));
}
f(10);

Nothing there but local lambdas.  If lambda isn't transparent in such
cases, then its value as something to safely desugar to is pretty weak.  
If yield does work, then we're capturing deep stacks.  A more plausible
example:

function j(x) {
   (lambda (y) {
      (lambda (z) {
         yield z;
       }
       (y + " and a dyne"));
    }
    (x + ", a poundal"));
}
print(j("I love you").next());

This is just a desugaring of some nested lets, but we still have yield
capturing many frames.  If this doesn't work, lambda is really useless.

For what it's worth, speaking as a long-time Scheme fan, I wouldn't add
lambda to ES.  It seems too similar to function; there will be endless
blog posts explaining the differences and motivation, mostly slightly
wrong.  The best ones will say, "Don't use it; just use function."  And
lambda introduces an awful lot of subtlety for something whose main
claim to utility would be in allowing precise and clear definitions of
new control constructs through desugaring.  Natural language is bad, but
not this bad.
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: How would shallow generators compose with lambda?

by David-Sarah Hopwood-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brendan Eich wrote:

> I think we missed an alternative that comports with Tennent's Oversold
> Correspondence Principle, *and* composes. Thanks to Dave Herman for
> pointing it out.
>
> function gen(x) {
>   foo( lambda (x) (yield x*x) );
> }
>
> need not yield from gen if the lambda is called from foo or another
> function -- it can throw the same error it would throw if the lambda
> escaped upward/heapward and was called after gen had returned. There's
> no requirement that yield not throw in any case where the lambda is not
> applied in the context of gen.

Well, that depends on what lambda is expected to be used for.

If it is expected to be used to implement general user-defined control
structures, then this restriction would prevent a yield from appearing
in the body of any such structure.

For the use of lambda in built-in expansions, OTOH, this would probably
be adequate, assuming the check that the lambda is called from the body
of the generator function is applied *after* expansion.

--
David-Sarah Hopwood  ⚥  http://davidsarah.livejournal.com

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: How would shallow generators compose with lambda?

by Dave Herman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

[Sorry for my absence lately.]

> If yield does work, then we're capturing deep stacks.  A more  
> plausible example:
>
> function j(x) {
>  (lambda (y) {
>     (lambda (z) {
>        yield z;
>      }
>      (y + " and a dyne"));
>   }
>   (x + ", a poundal"));
> }
> print(j("I love you").next());
>
> This is just a desugaring of some nested lets, but we still have  
> yield capturing many frames.  If this doesn't work, lambda is really  
> useless.

This issue really comes down to whether `lambda' is properly tail  
calling. If so, then the `yield' in this example occurs as if it were  
directly within the body of `j', because there's no stack beyond the  
activation frame of `j'.

To be a little more precise: when people refer to "Tennent," the main  
property they're talking about is that (modulo syntax) an expression E  
is equivalent to the expression (lambda () E)(). Namely, in any  
expression context (roughly, a position in a program where you can  
place an expression), either expression will result in the same  
program behavior.

If we don't want generators to capture deep stacks, then we can make  
it a dynamic error for `yield' to occur in a non-empty sub-stack. Then  
in order to preserve the property that (lambda () E)() for all E, we'd  
have to mandate that (lambda () E)() is really a tail call and  
guaranteed not to push any stack.

Alternatively, we could allow generators to capture deep lambda-
stacks, but not deep function-stacks.  However...

> For what it's worth, speaking as a long-time Scheme fan, I wouldn't  
> add lambda to ES.  It seems too similar to function; there will be  
> endless blog posts explaining the differences and motivation, mostly  
> slightly wrong.  The best ones will say, "Don't use it; just use  
> function."  And lambda introduces an awful lot of subtlety for  
> something whose main claim to utility would be in allowing precise  
> and clear definitions of new control constructs through desugaring.  
> Natural language is bad, but not this bad.

I hear you. I love lambda, I love the syntactic simplicity of  
Smalltalk blocks (and we could probably approximate its syntactic  
simplicity with a literal syntax), and I love the idea of adding a  
properly tail-calling function form. Nevertheless, I recognize that  
the similarity to `function' is a usability hazard.

Dave

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: How would shallow generators compose with lambda?

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On May 28, 2009, at 11:48 AM, Jim Blandy wrote:

> This is just a desugaring of some nested lets, but we still have  
> yield capturing many frames.  If this doesn't work, lambda is really  
> useless.

Dave replied, but I wanted to join in agreeing on the following:


> For what it's worth, speaking as a long-time Scheme fan, I wouldn't  
> add lambda to ES.  It seems too similar to function; there will be  
> endless blog posts explaining the differences and motivation, mostly  
> slightly wrong.  The best ones will say, "Don't use it; just use  
> function."  And lambda introduces an awful lot of subtlety for  
> something whose main claim to utility would be in allowing precise  
> and clear definitions of new control constructs through desugaring.  
> Natural language is bad, but not this bad.

I'm "cool" toward lambda, meaning not in favor. I'd rather reform  
function to the extent that doing so helps programmers. I'm not  
convinced that TCP matters a lot to those humans. To some programmers,  
and of course for macros and other things involving code generation  
and analysis, lambdas are great. But you can't please every(one|thing).

/be
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss
< Prev | 1 - 2 - 3 - 4 | Next >