Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.postscript > #2819
| From | Carlos <angus@quovadis.com.ar> |
|---|---|
| Newsgroups | comp.lang.postscript |
| Subject | Re: decoupled for-loop/iterator-variable construct |
| Date | 2016-09-19 15:03 +0200 |
| Organization | A noiseless patient Spider |
| Message-ID | <nronmb$erm$1@dont-email.me> (permalink) |
| References | <5a5eafe0-89fc-4a5f-b450-06b8db73c61e@googlegroups.com> <74bb3f1c-0602-46b6-b8cb-d2d78a237e68@googlegroups.com> <20160917150434.53428155@samara.DOMA> <09fb75fd-3dbf-4c34-a133-bae876266a70@googlegroups.com> |
On 18/09/2016 23:10, luser droog wrote:
> On Saturday, September 17, 2016 at 8:04:36 AM UTC-5, Carlos wrote:
>> [luser droog <luser.droog@gmail.com>, 2016-09-14 22:58]
>>> external iterator
>>
>> That's a great idea. I started to play with it, and I found it makes
>> a lot of things easier. I generalized it to a makeiterator function:
>>
>
> That's awesome! After two reads, I still only understand half of what
> you're doing. It's so far beyond what I was thinking.
It's not explained very well. I'll try to explain it below.
> Have you seen my loop that lets the user-proc `exit`?
> http://stackoverflow.com/documentation/postscript/6199/error-handling/21486/re-throwing-errors
That's what I was talking about. You need to do contortions to get
stack and dictionaries out of the way, and to ensure cleanup code is
ran, so the user's proc can run "transparently", ie, as if it ran in
the context of the calling place. But with an external iterator you
don't need to do any of this, because the user's proc actually does
run in the context of the calling place.
A function that runs a proc on each element of a sequence tries to
look like this:
{ PUT-NEXT-ITEM-IN-STACK USER'S-PROC } loop
but it needs a lot of auxiliary code because we are running
USER'S-PROC inside our own function and it needs to be invisible to
it.
But with an external iterator, what the user gets is just the function
PUT-NEXT-ITEM-IN-STACK, and it's the user themself who later puts it
inside a loop (if they want to):
{ PUT-NEXT-ITEM-IN-STACK ...my-code... } loop
So we don't have to care about the user's proc or the loop at all. (We
can help them with a little syntactic sugar. That's what the function
`done` does: it takes three procs, discards the second one and
arranges the other two in this way:
{ PROC-1 PROC-3 } loop
)
Here is an example of a simple ascending `for` iterator. This is the
signature:
% start inc end -> next hasnext?
It gets the usual iteration arguments and returns two procs: one to
put next item in stack, and another to check whether there is a next
item (otherwise the iteration has finished).
Here is the code:
% start inc end -> next hasnext?
/makeforiterator {
3 array astore % store (start inc end) in an array.
% we will use the first position to hold
% the current value (i).
/ARRAY exch def % store the array here, so we can use it
% later.
% now let's create the "hasnext?" proc. It will return true
% if i < end.
/hasnext? {
ARRAY aload pop % put the contents of the array in the stack.
% stack: i inc end
exch pop % discard inc. stack: i end
lt % return i < end
} def
% now the "next" proc. it will put i in the stack, and update
% ARRAY with i's new value
/next {
% first, let's check if the iteration didn't finish yet
hasnext? not { exit } if % if it did, exit.
ARRAY aload pop % put the contents of the array in the stack.
% stack: i inc end
2 index 2 index % stack: i inc end i inc
add % stack: i inc end i+inc
3 1 roll % stack: i i+inc inc end
% now we have in the stack: i (the value we want to leave
% for the user) and i+inc inc end (the updated iteration
% status).
ARRAY astore % store the new iteration status back in ARRAY
pop % now just i is left in the stack
} def
% now return both procs:
/next load
/hasnext? load
} def
Now the user can write:
1 2 3 makeforiterator
bind the procs:
/next? exch def /PUT-NEXT-ITEM-IN-STACK exch def
and use them in their own loop:
{ PUT-NEXT-ITEM-IN-STACK ...my-code... } loop
or use the helpful function `done`:
1 2 3 makeforiterator { ...my-code... } done
As you can see, there is a lot of boilerplate in
`makeforiterator`. The "array astore /ARRAY exch def" in the setup,
the "ARRAY aload pop" at the beginning of each proc, the check at the
beginning of /next, etc... We put all this in another function, which
will get just the variable parts:
- 3
the number of elements to store in ARRAY
- { exch pop lt }
a proc which gets three parameters (the result of `ARRAY aload
pop`) and returns true|false. This's the non-boilerplate part
of `hasnext?`
- { 2 index 2 index add 3 1 roll }
a proc that gets three parameters (the result of `ARRAY aload
pop`) and returns (a) the current element (b) the updated
iteration status, to be stored in ARRAY. This's the
non-boilerplate part of `next`.
and will fill the boilerplate. That's is what `makeiterator` does.
Now, of course we can't just store the array and procs in the current
dictionary. We have discussed before methods to insert objects
directly in code, like in this thread:
https://groups.google.com/d/msg/comp.lang.postscript/SjXE6-Azoz0/ZOWFzblMsrkJ
Then you came up with this
https://groups.google.com/d/msg/comp.lang.postscript/oQ3CNa0opWk/Dx_HYmAEAQAJ
which is much more simpler (just do it "by hand") and doesn't require
any support code. That's what I used in `makeiterator`. I just changed
things like
{ ARRAY aload pop ... }
to
[ /ARRAY load /aload cvx /pop cvx ... ] cvx
so ARRAY would be inserted directly in the code.
And I think that's all.
HTH.
--
Back to comp.lang.postscript | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-06-23 21:04 -0700
Re: decoupled for-loop/iterator-variable construct jdaw1 <jdawiseman@gmail.com> - 2016-09-11 16:49 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-11 20:58 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-13 18:52 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-14 22:58 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-14 23:01 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-14 23:02 -0700
Re: decoupled for-loop/iterator-variable construct Carlos <angus@quovadis.com.ar> - 2016-09-17 15:04 +0200
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-18 14:10 -0700
Re: decoupled for-loop/iterator-variable construct Carlos <angus@quovadis.com.ar> - 2016-09-19 15:03 +0200
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-19 10:56 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-19 11:35 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-09-19 11:42 -0700
Re: decoupled for-loop/iterator-variable construct luser droog <luser.droog@gmail.com> - 2016-10-01 13:59 -0700
csiph-web