Iteration and Recursion Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of...

Post on 01-Jan-2016

219 views 0 download

Transcript of Iteration and Recursion Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of...

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