24 March 2011

More on List combiners in Klink

Since the last post, I've implemented a sort of general listloop facility in Klink. It consists of:

• Two new T_ types
• A number of predefined styles (Two for now, easily expanded)
• A C function to create a listloop
• A C function to iterate a listloop

What it accomplishes

• It takes the place of a number of specialized loop facilities.
• It potentially can turn most map-like operations into streaming operations by changing just a few parameters. I haven't written that part yet, because promises are implemented but are not yet available in the C part of Klink.
• It can potentially build somewhat more powerful list loop functionality almost directly in C, again by just passing parameters. For instance, assoc, find, and position.
• It appears possible to reason about it in a fairly general way, for optimization purposes.

Dimensions of loop behavior

Last time, I spoke of two dimensions of looping: Family and Argument Arrangement. And a mea culpa: I was wrong to group $sequence with for-each. They are similar but$sequence returns its final value unless the list is circular, for-each' never does.

On further analysis, I ended up with more dimensions than that. I considered 9 dimensions of loop behavior, and ended up with 6 style parameters and 6 loop instantiation parameters, plus 2 parameters that are always supplied outside.

The dimensions of loop behavior are not independent. There are a few combinations that make no sense.

The dimensions themselves

From my design notes:

• Termination control
• Cases:
• When countdown is zero
• When arglist is empty
• When value is #t/is #f
• But for this case we also need an empty or countdown condition.
• Could be generalized to any eq? test, possibly useful for find.
• (Unlikely to need a case for when arglist is empty except for N elements, since neighbors is figured out by count first)
• The effective operative return value
• Cases:
• Map: Cons of value and accumulator
• Final value is reverse accumulator
• Boolean/reduce/sequence: Value itself
• Final value is value
• Each: No return value
• Terminator:
• Cases:
• Usually none
• Map: Reverse the value
• That's just reverse
• For-each: Give #inert
• Just curry the K_INERT value
• All can be done without reference to the loop object itself
• Treatment of the arglist(s). Cases:
• Use a single element (car, cdr remains)
• Use elements from multiple lists (car across, cdr across remains)
• Use multiple consecutive elements ((car, cadr), cdr remains)
• Other arguments to the operative
• Pass the accumulator too (reduce does this)
• This is really passing the previous value, which is sometimes an accumulator.
• Pass the index too
• Pass the "countdown" index too.
• Make the value the first arg in a list