function.sent beta equivalence?

Mark S. Miller erights at google.com
Wed Jun 24 22:20:39 UTC 2015


On Wed, Jun 24, 2015 at 3:17 PM, Mark S. Miller <erights at google.com> wrote:

>
>
>>> Jason Orendorff wrote:
>>>
>>>> Quick question about function.sent:
>>>>
>>>> As of ES6, there's this parallel between functions and generators:
>>>>
>>>>      // how to wrap a function
>>>>      // f2 is equivalent to f, if f doesn't use `this`.
>>>>      function f(...) { ... }
>>>>      function f2(...args) { return f(...args); }
>>>>
>>>>      // how to wrap a generator
>>>>      // g2 is equivalent to g, if g doesn't use `this`.
>>>>      function* g(...) { ... }
>>>>      function* g2(...args) { return yield* g(...args); }
>>>>
>>>> That is, λx.f(x) = f, a sort of beta-equivalence rule, and for
>>>> generators, you just need to add `yield*` to get an analogous rule. My
>>>> understanding is that this is one reason we have `yield*`. (Writing a
>>>> wrapping function/generator that also covers `this` is left as an easy
>>>> exercise.)
>>>>
>>>> Given function.sent, is there still a way to "wrap" a generator?
>>>>
>>>
>
>
>> On Wed, Jun 24, 2015 at 2:17 PM, Brendan Eich <brendan at mozilla.org>
>> wrote:
>>
>>> Hrm, the meeting notes don't quite capture it (
>>> https://github.com/tc39/tc39-notes/blob/bf5190257d22d1c700e203b28edc8d85ee3aadcc/es6/2015-05/may-27.md
>>> is one view; my fault for not editing after), but we have discussed passing
>>> function.sent into the sub-generator in the past. Ben Newman first raised
>>> the idea the other year, but we finally all came to see at the last (May)
>>> meeting that there's no good way to do it in general.
>>>
>>> When you write a delegating generator that does nothing else, it's
>>> tempting to want function.sent delegation. But in general the yield* could
>>> want a different first-next param than what was passed down, especially
>>> when the delegator looks like this:
>>>
>>>   function *g2(...args) { prolog code here; maybe-return yield*
>>> g(...args); optional epilog here }
>>>
>>> See the discussion from the May meeting, I'll cite it here:"""
>>>
>>> MM: But it's passing something from before when yield * is evaluated.
>>>
>>> DH: I'm beginning to think that this is the wrong path (passing in
>>> function.next via yield *).
>>>
>>> AWB: You could create some kind of wrapper if you wanted to pass in the
>>> first value to the subgenerator.
>>>
>>> MM: Libraries could do this.
>>>
>>> yield  *  wrap(g,function.next);
>>>
>>> MM: "wrap" returns an iterator which wraps the generator which primes
>>> the subgenerator with the supplied value.
>>> """
>>>
>>> Does this make sense? Sorry again for sparse notes.
>>>
>>> /be
>>>
>>>
> Something strange and bizarre that Jafar and I just discovered after the
> TC39 meeting:
>
> We all know that there are a set of conventional combinators, like
> flatMap, that work fine for iterators.
>
> Iterators are uni-directional. Generators are bi-directional. (As Jara
> observes: Generator implements Iterator, Observer)
>
> We thought that these combinators did not apply to generators in their
> full bidirectional glory. We were wrong.
>
> Flatmap of generators can approximately be modeled in terms of "yield*
> wrap" as follows:
>
> flatMap([g1, g2]) is equivalent to
>
> (function*() {
>   yield* wrap(g1, function.sent); // result of g1 ignored!
>   return yield* wrap(g2, function.sent);
>

I think this second yield* should just be

      return yield* g2;



> }())
>
>
>
> On Wed, Jun 24, 2015 at 3:04 PM, Jason Orendorff <
> jason.orendorff at gmail.com> wrote:
>
>> On Wed, Jun 24, 2015 at 2:17 PM, Brendan Eich <brendan at mozilla.org>
>> wrote:
>> > MM: Libraries could do this.
>> >
>> > yield  *  wrap(g,function.next);
>> >
>> > MM: "wrap" returns an iterator which wraps the generator which primes
>> the
>> > subgenerator with the supplied value.
>>
>> Thanks for finding this discussion. This is exactly what I'm
>> interested in. What does "wrap" look like? It seems like it would be
>> pretty involved.
>>
>
> Just showing the next method:
>
> function wrap(g, prime) {
>   let first = true;
>   return {
>     next(val) {
>       if (first) {
>         first = false;
>         return g.next(prime);
>       } else {
>         return g.next(val);
>       }
>     }
>     //...
>   };
> }
>
>
> ALL CODE I WROTE ABOVE IS UNTESTED.
>
> Does this make sense? If anyone tests it, does it work?
>
>
> --
>     Cheers,
>     --MarkM
>



-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150624/dc2ecdd7/attachment.html>


More information about the es-discuss mailing list