OK, so now a side issue. We already have an iterator:

        slice_range first last

so you can already write:

        for i in slice_range first last do .. done

The problem here is that the implementation of a loop for an argument value D is

        var it = iterator D;
        label:>>
                var maybe_index = it ();
                match maybe_index with
                | Some ?index => 
                        i = index; 
                        body;
                        goto label;
                | None => ;
                endmatch;

So this does: apply function named "iterator" to D to get the iterator
closure into variable it.

Now apply the iterator to () to get a value. If it's Some thing then
assign the thing to the loop index, execute the body, and branch
back, otherwise just drop thru.


The processes a stream of Some's until it gets a None.

An option type in general requires a heap allocation. The iterator
itself is a C++ object with an apply() method. The match has to do
some munging too.

The point? This isn't very efficient. It's fine for "scripting" but not so
good for high performance numerical work.

There are a couple of solutions. The first one is what we already have:
use a low level loop. The second one is to get the parser to recognize
the special case of an integer subrange (given literally of course)
and do a low level loop. 

The third one is to INLINE the generator. Which leads to the question:
HOW do you inline an generator?

So what must happen is: when the generator gets to yield, the next instruction
address has to be saved. Then we jump into the loop. For a simple loop
we go to the beginning. At the end of the loop, we jump back to the saved
address in the generator.

When the generator does a return None, we just jump past the end of the loop.

Now, since a generator MUST yield and return from the top level (you cannot
do it inside a nested block because there are no nested blocks, only nested
functions/procedures, so if you try this you're yielding from the wrong 
function).

So the generator can easily be converted to a procedure, with the yield
assigning to the loop control variable (directly, no "Some") and jumping
into the loop.

Since a loop can also call the same generator in its body, we either have
to not optimise (if we can even detect this!) or change the semantics so
a call to the generator saves the address in the loop body, and then the
generator has to jump there (not the beginning).

So in summary .. we need two "program counters" one for the generator
and one for the loop body, and we jump back and forth between the two.

Hardly surprising .. you did know they're coroutines right!!

So here's the FUN thing. The instruction we need is

        Branch and Link.

>From the PDP-11. given two registers PC1 and PC2 then:


        label: BL PC1, PC2

does this:

        PC2 = PC + 1 // next address
        PC = *PC1  // GOTO

For example:

        BL iterator, body

will jump to the iterator (last location) and save the next instruction
position in the body in body. The iterator then does

        BL body, iterator

to swap back.

I believe this will work for any number of coroutines. Note these are NOT
fibres: the control exchange is always to a KNOWN target. There's no
data exchange, hence no "read/write" direction, and no non-determinism.


--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
WatchGuard Dimension instantly turns raw network data into actionable 
security intelligence. It gives you real-time visual feedback on key
security issues and trends.  Skip the complicated setup - simply import
a virtual appliance and go from zero to informed in seconds.
http://pubads.g.doubleclick.net/gampad/clk?id=123612991&iu=/4140/ostg.clktrk
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to