Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.postscript > #2817

Re: decoupled for-loop/iterator-variable construct

From Carlos <angus@quovadis.com.ar>
Newsgroups comp.lang.postscript
Subject Re: decoupled for-loop/iterator-variable construct
Date 2016-09-17 15:04 +0200
Organization A noiseless patient Spider
Message-ID <20160917150434.53428155@samara.DOMA> (permalink)
References <5a5eafe0-89fc-4a5f-b450-06b8db73c61e@googlegroups.com> <74bb3f1c-0602-46b6-b8cb-d2d78a237e68@googlegroups.com>

Show all headers | View raw


[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:

% obj1...objn n procnext procnext? -> userprocnext userprocnext?

You pass to it:
 - some objects you need to keep track of the iteration
 - n, the number of objects
 - a proc, which gets those objects and returns the next iteration
   item(s) and a new set of objects with the updated iteration status
 - another proc, which receives the objects and returns whether there
   are more items

and it returns two procs that don't take any arguments:
 - one that returns the next iteration item(s)
 - and one that returns true or false, whether there is a next iteration
   item

For example, a function to create "for" iterators like yours would be
constructed this way:

% start inc end -> next next?
/foriter {
    3
    % i inc end -> i  i+1 inc end
    { 2 index 2 index add 3 1 roll }
    % i inc end -> t|f
    { exch 0 lt { gt } { lt } ifelse }
    makeiterator
} def

  GS> 1 3 6 foriter
  GS<2> /next? exch def   /next exch def
  GS>next =
  1
  GS>next? = 
  true
  GS>next =
  4
  GS>next?
  false

I struggle writing functions that take procs and execute them inside
loops without stack or dictionary interference. With external iterators
that problem doesn't exist anymore! You just have to yield the next
value, and let "{ } loop" take care of the looping.

With a little syntactic sugar (the function "done") to hide the
details they almost look like control structures:

  GS>(External iterators are great) 9 eachslice { == } done
  (External )
  (iterators)
  ( are grea)

I think this idea can be extended to filters and mappers. I'll get into
it when I get tired of writing all kind of iterators :)

Here is the code of makeiterator and done, and a couple of iterators:

% obj1...objn n nextproc next?proc -> unextproc unext?proc
/makeiterator {
    4 dict begin
    /next?proc exch def  /nextproc exch def
    array astore /arr exch def
    /unext? [
        /arr load /aload cvx /pop cvx
        /next?proc load /exec cvx
    ] cvx def
    [ /unext? load /exec cvx /not cvx { exit } /if cvx
      /arr load /aload cvx /pop cvx /nextproc load /exec cvx
      /arr load /astore cvx /pop cvx ] cvx
    /unext? load
    end
} def

% next next? proc -> -
/done {
    exch pop
    % { next proc } loop
    [ 3 1 roll  /exec cvx exch 1 index ] cvx
    loop
} def

% start inc end -> next next?
/foriter {
    3
    % i inc end -> i  i+1 inc end
    { 2 index 2 index add 3 1 roll }
    % i inc end -> t|f
    { exch 0 lt { gt } { lt } ifelse }
    makeiterator
} def

% arr -> n n?
/eachwithindex {
    0 2
    % arr i -> arr[i] i  arr i+1
    { 2 copy get  1 index  4 2 roll 1 add }
    % arr i -> t|f
    { exch length lt }
    makeiterator
} def

% arrayn ... array1 n -> nextproc next?proc
/eachinparallel {
    % get minimum length
    1 dict begin
    /n exch def
    dup length  1 1 n { index length 2 copy gt { exch } if pop } for
    0 n  % an...a1 len idx n
    n 3 add
    end
    % an...a1 len i n -> an[i]...a1[i]  an...a1 len i+1 n
    { 2 dict begin
      /n exch def  /i exch def
      n -1 1 { index i get n 2 add 1 roll } for
      i 1 add  n
      end
    }
    % an...a1 len i n -> t|f
    { 3 1 roll gt
      exch { exch pop } repeat
    }
    makeiterator
} def

% arr slicesize -> next next?
/eachslice {
    0 3
    % arr n i -> arr[i..i+n]  arr n i+1
    { 3 copy  exch getinterval  4 1 roll
      1 index add }
    % arr n i -> t|f
    { add  exch length le }
    makeiterator
} def


-- 

Back to comp.lang.postscript | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


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