Pyli/Methods/For
Contents
Not Any More
I have decided to go away from the bulky for syntax and to something much simpler.
The programmer will be presented with a bunch of tools that will all work together that can be assembled to read something like what for would read like.
The tools would be based around the idea of an iterator, which includes:
- range iterator: from one value to another, progressing somehow.
- Vector iterator
- Dict key or value or item iterator
- String iterator (through each character)
- generator that gives how to calculate the next value, whether to continue, etc...
- flip-flops: True until some condition is reached, False until another condition is reached, etc...
- user-defined iterators
Then there would be several useful functions that use these iterators seamlessly:
- for: Go through each item, doing something with it, and throwing away the results
- map: Go through each item, doing something with it, and keeping the result as a new iterator
- filter: Go through each item, keep only the ones that you want to, possibly modifying them.
- reduce: Go through each item, gradually building up a final result.
In this system:
- Python's for loop is unchanged.
- map, filter are necessary. (Although I really like Python's comprehensions)
- while is just another case of a for loop: (for (flip-flop &True) ...), (for (flip-flop &(> x 5) ...)
See Pyli/Iterators for more info.
For Loops
The for loop takes on most of the functionality of the loop in Common Lisp, as well as dotimes, dolist, and while. It also does the duty of both comprehensions and generator syntax in Python.
(for each-clauses test-clauses body-clauses terminating-clauses result clauses)
Iterating For Loops
There are two kinds of for loops. Non-iterating for loops will work through the entire loop and return a single result. Iterating for loops will return an iterator. Calling next on the iterator will yield the next value from the for loop.
The distinguishing characteristic between non-iterating and iterating for loops is the presence of the yield call.
Each Clauses
This controls how each iteration is prepared. All each clauses are compatible with iterating and non-iterating loops.
Using iterators:
- x in y [as as-expr]: Iterates through each item in y.
- x in (range 10): Iterates from 0 to 9. range is a common function.
- (x (y z) a b) in c: Destructuring should work as well.
Using range:
- x [up|down] [from a] [to b] [step c] [as as-expr]:
- up: Signals step to be +1. (default) Excludes down, step.
- down: Signals step to be -1. Excludes up, step.
- from a: Start at a.
- to b: End at b-1.
- step c: Take steps in increments of c.
- as as-expr: Interpret the value before assigning to x. For instance: (for x to 10 as (* x x) ...) will count 0, 1, 4, 9, etc...
Using expressions:
- x = expr [then then-expr] [as as-expr]: Calculates a new value for x given the expression each time. If there is a then-expr, then it is used for subsequent iterations.
Repeat count:
- repeat n: Repeat the loop up to n times.
Test Clauses
Unlike the terminating clauses, these clauses will skip iterations that do not satisfy conditions. These are compatible with iterating and non-iterating loops.
- if cond: Only do this iteration if the condition is satisfied.
- unless cond: Only do this iteration if the condition is not satisfied.
Body Clauses
These are all compatible with a single value (non-iterating for loop):
- do ...: Performs the action each time.
- append a in b: Appends the value of a in b. b starts off as an empty vector if it is not specified.
- count a in b: If a is True, increment b by 1.
- sum a in b: Stores the cumulative sum of a in b.
- product a in b: Like sum but for products.
- max a in b as c: Finds the max of a and stores c in b.
- min a in b as c: Finds the min of a and stores c in b.
But if you use yield, then it turns into an iterating for loop:
- yield val: This turns the for loop into something that will evaluate into a single value into something that will evaluate into an iterator. Each iteration will return the value of the next yield statement.
Terminating Clauses
These simply signal when to end the iteration. These are compatible with iterating and non-iterating for loops.
- until cond: Keep iterating until the condition is true.
- while cond: Keep iterating until the condition is false.
Returning Clauses
These clauses control what is returned. This is not compatible with iterating for loops.
- returning x: Returns x when the loop terminates
If there is an obvious return value, it will use that if one is not specified.
Examples
The syntax is pretty complicated, but compact.
This will sum all the elements in a.
(for i in a sum i)
This will find the largest element in a.
(for i in a max i)
This will find the element in a that maximizes f:
(for i in a max (f i) as max-i)
This will find the element in a that maximizes f but also satisfies c:
(for i in a if (c i) max (f i) as max-i)
This will return an iterator that will yield only the elements of a that satisfy c: (same as filter in Python.)
(for i in a if (c i) yield i)