Post on 01-Jan-2016
Iteration and Recursion
Prepared by
Manuel E. Bermúdez, Ph.D.Associate ProfessorUniversity of Florida
Programming Language PrinciplesLecture 21
Iteration
• Execute a block multiple times for its side effects.
• Enumeration controlled loops:• Execute a block for every value in a
finite set.• Fortran:
do 10 i=1,10,2 ... 10 continue :
Classic Problems in Fortran
• 'do' as prefix of assignment:
do7i=j+3*4,20 do loop do7i=j+3+4 assignment
'do7i' is a valid identifier. 'do' not a reserved word in Fortran. Need to look ahead arbitrary
distance, to the 'comma'.
Classic Problems in Fortran (cont’d)
• Loop body can change the loop index:
do 10 i=2,20 i=i-1 10 continue infinite loop
• Goto's can jump into the middle of a loop. • So what's the value of the index,
in that case ??
Classic Problems in Fortran (cont’d)
• If goto branches out of loop, value of i is last assigned. If loop terminates normally, value of i is implementation-defined.• Last increment of i can cause overflow:
negative value ??? • Fortran loop is bottom-tested: loop body
will execute at least once.
Pascal
• (and Modula, and most languages with enumeration controlled loops):
for i := first to last by step do
begin
...
end;
Pascal (cont’d)
• Questions:1. Can i, first or last be modified in the loop?
• If so, what is the effect?2. What if first > last?3. What 's the value of i when done?4. Can one jump from outside, into the loop?5. What if first has a side effect on i, or on
last, or vice-versa?
Pascal (cont’d)
• Most languages prohibit modifying the loop index.• Very expensive to check at compile
time. Need to check for:• Assignments to i• Nested loops that use i.• Passing i to a procedure by
reference.• Reading i.
Pascal (cont’d)
• What does this Pascal for statement do?
i := 7; for i := i+1 to i+8 do
begin
...
end;
• What if instead of i+1, we had f(i), where
f takes i as a reference parameter ?
Modern For Loops Are Top-Tested
Modern For Loops Are Top-Tested (cont’d)
• Works only for positive steps.
• In Pascal, for i := 10 down to 1 do ...• In Ada, for i in reverse 1..10 do ...• In Modula, FOR i := 10 to 1 STEP -1
compile-time constant
Modern For Loops Are Top-Tested (cont’d)
• In Fortran• No "backward" syntax,• Compile-time constant steps not required.• Can use an "iteration count“
Modern For Loops Are Top-Tested (cont’d)
• In C, C++, Java, it's simple. No loop index.
for (e1; e2; e3) body; Code is:
e1;L2: if not e2 goto L1 body e3; <--- any 'continue' branches here goto L2L1: ...
Modern For Loops Are Top-Tested (cont’d)
• NOT equivalent to:
e1; while (e2) { body; /* if this contains a 'continue', */ e3; /* e3 is not executed */
}
Modern For Loops Are Top-Tested (cont’d)
• In C, programmer's responsibility:
• effect of overflow.• index, other variables, can be
modified inside loop.• e1, e2, e3 are all optional. If e2 is
missing, it's considered to be a 1 (true).
Access to the Index Outside the Loop
• Fortran IV, Pascal, leave the loop index undefined.
• Fortran 77, Algol 60, leave the "last value assigned".
• In Pascal,
var c: 'a' .. 'z'; for c := 'a' to 'z' do begin ... end; (* what's the value of c ? *)
Access to the Index Outside the Loop (cont’d)
• Compiler forced to generate slower code
• Two branches in each iteration
Access to the Index Outside the Loop (cont’d)
• Several languages (Algol W, Algol 68, Ada, Modula-3, new ISO C++):
• loop header *declares* loop index.• loop index's type is inferred from
loop bounds.• not visible outside the loop.
Combination Loops
• Algol 60 allows a 'for-list' of enumerated values/ranges.
• Syntax:
Stmt 'for' id ':=‘ Enumerator list ',' 'do' Stmt
Enumerator Expr
Expr 'step' Expr 'until' Expr
Expr while Condition
Combination Loops (cont’d)
• Examples (all three are equivalent):
for i := 1, 3, 5, 9 do ... for i := 1 step 2 until 10 do ...
for i := 1, i + 2 while i < 10 do ...
Iterators
• An iterator allows examination of the elements in a data structure, one at a time.
• Various kinds of iterators available in Clu, Icon (see textbook).
• Java has a built-in iterator class.
Iterator Methods in Java
Iterator ix = x.iterator();
• Constructs and initializes an iterator for the elements of x.
• ix is the new iterator.
• The class for x must define the iterator() method.
Iterator Methods in Java (cont’d)
ix.hasNext()
• Returns true iff x has a next element.
ix.next()
• Return next element;• Throws NoSuchElementException if
there is no next element.
Iterator Methods in Java (cont’d)
ix.remove()
• Removes last element returned by ix.next().
• Throws UnsupportedMethodEXception if method not implemented.
• Throws IllegalStateException if ix.next() not yet called or did not return an element.
Using the Iterator
Iterator ix = x.iterator();
while (ix.hasNext())
examine(ix.next());
• Much better than
for (int i=0; i<x.size(); i++) examine (x.get(i));
Advantages of Iterators
• More abstraction. Object class "knows" how to iterate.
• Often possible to implement next() more efficiently than get(). Example: linked list.
• Data structures often have no get-by-index method.
"Faking" an Iterator in C
• Using a "fake" iterator in C:
• C code for the binary tree pre-order traversal iterator (see textbook).
Logically Controlled Loops
• Semantically less complex (fewer subtleties).
• Execute statement (or block) until a condition becomes true/false (while)
• Variations (syntactic sugar of each other):
Logically Controlled Loops (cont’d)
while condition do block; (Pascal, Modula) while (condition) block; (C, C++, Java)for i := irrelevant_expression
while condition do statement (Algol)
10 if negated-condition goto 20
block
goto 10
20 (Fortran)
Logically Controlled Loops (cont’d)
• Post-tested loops (execute at least once):
repeat statements until condition (Pascal)
do statement while condition (C, C++, Java)
Mid-Tested Loops (Quit Anytime):
loop statement_list when condition exit statement_list when condition exit ...
end (Modula-1)
• 'exit' is built in, along with 'when', so exiting from a nested construct is impossible.
Modula-2
• Favored a simple EXIT Statement
LOOP
line = ReadLine; IF AllBlanks(line) THEN EXIT END; ConsumeLine(line) END;
• EXIT statements are only allowed to appear inside LOOPs.• Difficult to enforce.
Modula-3
• EXIT can abort a WHILE, REPEAT, or FOR loop.
C:
for (;;) { line = read_line(stdin); if (all_blanks(line)) break; consume_line (line); }
C Loops
• [M. Scott says "for some reason, for(;;) has traditionally been favored over the equivalent while (1)".
• The actual original reason was efficiency, not style:• older compilers would actually test the 1 each time around the while loop.
• With today's compilers, it should make no difference.
Mid-Tested Loops (cont’d):
• Euclid, Ada:
loop ... exit when condition; end loop;
Mid-Tested Loops (cont’d):
• Java:• loops can be labeled,• 'break' statement has optional label.
outer: while (true) { get_line(line); for (i=1; i<=length; i++) if line[i]='#' break outer; consume_line(line); }
Recursion
• Any iterative formulation can be expressed as recursion, and vice versa. They are equally powerful.
• Some functional languages do not allow iteration.
• Iteration often more efficiently implemented.
Recursion (cont’d)
• Optimizing compilers for functional languages usually generate very good code.
• The use of iteration/recursion is mostly a matter of ease of use:
• Iteration more efficient than recursion ?• Naive implementations are.
Recursion (cont’d)
• For some problems, iteration seems natural.
for (i=low; i<=high; i++) total += f(i);
• For other problems, recursion seems more natural:
let gcd a b = a eq b -> a | a < b -> gcd a (b-a) | gcd (a-b) b
Recursion (cont’d)
• In C,
int gcd (int a, int b) { if (a==b) return a; else if (a > b) return gcd(a-b,b); else return gcd(a, b-a); }
• In both cases, the choice could go the other way.
Recursion (cont’d)
• Summation in C, recursive:
typedef int (*int_func) int;
int summation (int_func f, int low, int high) {
if (low == high) return f (low)
else return f(low) + summation(f, low+1,high);
}
Recursion (cont’d)
• GCD in C, non-recursive:
int gcd(int a,int b) {
while(a!=b) if (a > b) a = a - b; else b = b - a; return a; }
Tail-Recursion
• Additional computation never follows a recursive call. (nothing done as recursion unwinds).
• No need to allocate stack space dynamically: we can reuse previous space.
• Continuation-passing style: • can always avoid doing work after
recursive call by passing that work into the recursive call, a continuation.
Tail-Recursion (cont’d)
• Example (RPAL):
let rec f n = n eq 1 -> 1 | n * f (n-1) in f 3
let f n = rf n 1 where
rec rf n r = n eq 1 -> r | rf (n-1) (n*r)in f 3
Tail-Recursion in Scheme
Tail-Recursion (cont’d)
• Recursion does not lead to algorithmically inferior programs.
• Instead, the style of programming just changes (paradigmatically).
Fibonacci tail-recursion (Scheme vs. C)
Applicative and Normal-Order Evaluation
• Called Normal Order and PL Order in RPAL.
• Normal order (passing unevaluated parameters) is used for macros in C.
Applicative and Normal-Order Evaluation (cont’d)
• Example:
#define DIVIDES(n,a) (!((n) % (a))) /* true iff n % a is zero */
• Preprocessor replaces
DIVIDES (x,y+z)
(textually!, no evaluation) with
(!((x) % (y+z)))
Applicative and Normal-Order Evaluation (cont’d)
• Parentheses (n), (a) are crucial. Without them,
DIVIDES (x,y+z)
is replaced with (!(x % y+z))
which is equivalent to
(!((x % y)+z))
Applicative and Normal-Order Evaluation (cont’d)
• Macros are problematic:
#define MAX(a,b) ((a) > (b) ? (a) : (b)
MAX(x++, y++)
will increment either x (or y) TWICE !
Applicative and Normal-Order Evaluation (cont’d)
• Advantage of macros:
• Efficient ! No function call overhead.
• In C++, 'inline' tells compiler to try to convert function call to a macro.
• Algol 60 uses normal order, with PL order also available.
Non-Determinacy
• Construct in which the choice between alternatives is deliberately unspecified.
• Example:
n + n++ in C
(order of evaluation unspecified)
Non-Determinacy (cont’d)
• Sometimes makes it easier to reason about program.
• Mostly a set of guarded commands from which any guard that is true can be selected.
Non-Determinacy (cont’d)
• Example (SR, adopted Dykstra's guarded command):
if a >= b -> max := a; [] b >= a -> max := b; fi
• Nondeterministic choice made among guards that evaluate to true.
Non-Determinacy (cont’d)
• Also used for loops:
do a > b -> a := a - b; [] b > a -> b := b - a; od gcd := a
• Loop quits when no guard is true.• We wish to ensure fairness: each candidate
equally likely to execute.
Iteration and Recursion
Prepared by
Manuel E. Bermúdez, Ph.D.Associate ProfessorUniversity of Florida
Programming Language PrinciplesLecture 21