Title: CS
11321
2CS1321Introduction to Programming
- Georgia Institute of Technology
- College of Computing
- Lecture 23
- November 13, 2001
- Fall Semester
3Todays Menu
- Breaking the Functional Paradigm
- (let )
- (set! )
- Iteration
- Vectors
4Breaking the Functional Programming Paradigm
5Local Scope, revisted
Several lectures ago, we introduced the idea of
scope and how to create different areas of
influence within our Scheme environment by
utilizing the (local ) function. (local )
allowed us to create new functions and variables
that existed only within the scope of the
local. (local ) is not part of the official
R5RS. It exists only as a DrScheme function.
So is there an equivalent function in standard
scheme that allows us to create local functions
and variables?
6(let )
The real version of (local ) is the (let )
function. (let ) resembles (local ) greatly
(local (define ltnamegt ltvaluegt)
(define ltnamegt ltvaluegt) (define
ltnamegt ltvaluegt) ltexpressiongt)
(let (ltnamegt ltvaluegt) (ltnamegt ltvaluegt)
(ltnamegt ltvaluegt)
ltexpressiongt)
7So whats the difference?
- To create function definitions, it becomes
necessary to use lambda bodies.
(let ( a (lambda (y)
( y 1))) ( b 1)
(a b))
8So whats the difference?
- (let ) does not guarantee order. Compare the
following two statements
(let (a 1) (b 2) (c ( a b))
c)
(local (define a 1) (define b 2)
(define c ( a b)) c)
9So why on Earth should we talk about (let )?
- (let ) is a function that exists in all
distributions of Scheme. (local ) only exists
in the Language Levels of DrScheme. - (let ) has a very similar format to a concept
were going to introduce in another few slides.
Unless you are working with Full Scheme or on a
problem that specifically directs you to do so,
you are not required to use (let ) instead of
(local ).
10(set! )
(set! ltnamegt ltnew valuegt)
(set! ) has a very simple purpose it changes
the values stored in existing variables to new
values. One important thing to note (set! )
returns NOTHING. It merely affects the value
associated with the name supplied.
Confused? Lets look at some examples
11Lets start with a brand new blank slate
12Whoa! What happened?
(set! ) cannot create new definitions. It can
only change existing names.
13Ok. That worked. But we cant see exactly what
we did!
(set! ) does not return a value. It only
affects the value associated with a name.
14Now we can see what our call to (set! ) actually
did.
15(set! ) Advance Student Restrictions
Advanced Student mode places one additional
restriction on the use of (set! ) We cannot
call (set! ) on any value that is not a global
value or a result of a call to (local ) or (let
).
16Repeating Ourselves
By this point in the semester, were all very
familiar with functions such as this
17Repeating Ourselves
By this point in the semester, were all very
familiar with functions such as this
We could easily identify the three components of
recursion in this function (1) the termination
condition, (2) the recursive call, and (3)
the reduction step
18Repeating Ourselves
By this point in the semester, were all very
familiar with functions such as this
(1)
(3)
(2)
We could easily identify the three components of
recursion in this function (1) the termination
condition, (2) the recursive call, and (3)
the reduction step
19Repeating Ourselves
Recently we explored a new form of recurring
through a process that involved carrying our
calculation with us as we recurred
20Repeating Ourselves
Recently we explored a new form of recurring
through a process that involved carrying our
calculation with us as we recurred
21Repeating Ourselves in a New Way
Despite the addition of an accumulator parameter,
tail recursion is still recursion We are
calling the function that we are writing in the
body of our code. There is an alternative to this
process that shares many of the same principals
as tail recursion, but is in fact not a recursive
process. This alternative is called a loop. In
Scheme, they are implemented with a call to the
(do ) function.
22(do ) loops
Conceptually, a (do ) loop isnt that different
from a recursive process. Both a loop and a
recursive process repeat a task over and over
until some termination condition is met and a
final action (or series of actions) can be
performed.
23(do ) loops
The difference between the two lies in the notion
that a recursive process calls itself in its body
of code. The function launches itself into an
entirely new function call. A loop does not
call itself. It essentially loads a body of
code and repeats that body of code until it
finishes. It never leaves the function in the
way a recursive process does.
24(do ) loops
- The do loop has three main components
- An initialization section in which it creates any
additional variables it might need (as necessary)
and also specifies any optional rules for
updating those variables. - A test termination section in which the loop
determines if it has finished its task and can
perform a final action. - A body of code to execute repeatedly (if
necessary).
25(do ) loops
(do ( ltnamegt ltvaluegt
ltoptional update expressiongt) (
ltnamegt ltvaluegt ltoptional update expressiongt)
( ltnamegt ltvaluegt ltoptional update
expressiongt) lttermination testgt
ltfinal action(s)gt a body of code
)
26(do ) loops
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
Here we create any additional variables we might
need to perform our calculation, along with an
update expression.
27(do ) loops
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
Here we specify a termination condition. Once
that condition is met, we specify a final action
(or action) we want to perform.
28(do ) loops
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
Here we specify a body of additional code that we
wish to execute repeatedly. It is very possible
to have this section be empty!
29How This Works
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
We enter into the body of the do-loop code
30How This Works
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
We create any additional variables we need and
give them initial values.
31How This Works
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
We then perform our termination test. If it
resolves to true, we perform our final action(s)
and return the result of that action. (This
could be as simple as returning a value weve
been calculating!)
32How This Works
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
If the termination test fails (meaning were not
supposed to stop), we execute the body of code
and loop around.
33How This Works
(do ( ltnamegt ltvaluegt ltupdate
expressiongt) ( ltnamegt ltvaluegt
ltupdate expressiongt) ( ltnamegt
ltvaluegt ltupdate expressiongt)
lttermination testgt ltfinal action(s)gt
a body of code )
As we loop around, we update our variables with
our update expressions as necessary. The results
of our update expressions are then stored in the
variables. We continue on to the termination
test. The update expressions have some
interesting rules, but well explain them in our
upcoming example.
34Enough Theory. Lets code!
Weve seen the summation function using both
regular and tail recursion. Why not take a stab
at it using loops?
35sum-loop
(define (sum-loop n) (do
Again, the first component of our loop is an
initialization and update section. Much like in
tail recursion, we create a result or
accumulator variable that we seed with an
initial value.
36sum-loop
(define (sum-loop n) (do ( result 0 )
Lets leave the update expression up in the air
for now. Do we need any additional variables?
37sum-loop
Here weve duplicated the value n that we passed
in to our function. If we think back to our
recursive functions, we were always decrementing
our n value by one as we recurred. As we cant
perform any side effects like (set! ) to a
parameter, it might not be a bad idea to
duplicate our values.
(define (sum-loop n) (do ( result 0 )
( count-down n )
38sum-loop
Here weve put our terminating condition. If
weve counted all the numbers between n and 0,
perform some final action and terminate.
(define (sum-loop n) (do ( result 0 )
( count-down n ) (
count-down 0)
39sum-loop
What body of code could we need? Before we can
answer that, we need to look at those updating
expressions again
(define (sum-loop n) (do ( result 0 )
( count-down n ) (
count-down 0) )
40sum-loop
Each time we loop around, we want to update our
result. How? Well add the current value of
count-down to result.
(define (sum-loop n) (do ( result 0 )
( count-down n ) (
count-down 0) )
41sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
) ( count-down 0)
)
Each time we loop around, we want to update our
result. How? Well add the current value of
count-down to result.
42sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
) ( count-down 0)
)
- This statement gets into our set of rules for the
variables in an update expression. - The variables cannot reference each other during
the initialization phase. - During the update phase, you can use only the
last value for a variable in a calculation,
regardless of what happens to that variable now.
43sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
) ( count-down 0)
)
Each time we loop around, also want to change our
count-down value. How??
44sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
(- count-down 1)) ( count-down 0)
)
Each time we loop around, also want to change our
count-down value. Decrement by 1.
45sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
(- count-down 1)) ( count-down 0)
result )
When we exit our loop, we want to return our
calculation, right? So
46sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
(- count-down 1)) ( count-down 0)
result )
So what does that leave our body of code to do?
47sum-loop
(define (sum-loop n) (do ( result 0 (
result count-down)) ( count-down n
(- count-down 1)) ( count-down 0)
result )
Absolutely nothing. We already have result
totaling values for us, and count-down counting
down from n to 0 for us. Believe it or not,
this is not an uncommon experience when working
with Scheme loops.
48sum-loop2 with a body of code
(define (sum-loop2 n) (do ( result 0 (
result count-down)) ( count-down n
(- count-down 1)) ( count-down 0)
result )
But what if I wanted to have a body of code.
Couldnt we use (set! )?
49sum-loop2 with a body of code
(define (sum-loop2 n) (let ((result 0))
(do ( count-down n (- count-down 1))
( count-down 0)
result (set! result ( count-down result))
) ))
Yep. Here weve taken out the initialization of
result from the loop and put the update
expression explicitly in the body of the loop.
50sum-loop2 with no initialization
We can even eliminate the initialization section
all together. This is a useful ability since it
is possible that we want to deal with
pre-existing variables at times within our loop.
(define (sum-loop2 n) (let ((result 0)
(count-down n)) (do
( count-down 0) result
(set! result ( count-down result)) (set!
count-down (- count-down 1)) )
))
51sum-loop2 with no initialization
(define (sum-loop2 n) (let ((result 0)
(count-down n)) (do
( count-down 0) result
(set! result ( count-down result)) (set!
count-down (- count-down 1)) )
))
Notice that the loop actually executes 2 lines of
code in a row in the body of code! Can have many!
52sum-loop3 alternatively with no updates
(define (sum-loop3 n) (do (result 0)
(count-down n) ( count-down 0) result
(set! result ( count-down result)) (set!
count-down (- count-down 1)) ) )
Notice the lack of update statements. We can
choose to do the updating within the body
instead.
53Thinking about loops
One thing we have seen many times this semester
is a number of functions that have been shaped by
the type of data coming into them. Structural
recursion on a list is one example. Working
with Scheme structures is another.
54Thinking about loops
So what is the point of loops? We can adapt our
loop syntax to work with dynamic data structures
such as lists, but it gets messy dealing with
moving through the data. Loops are better at
working with data where we concretely know where
the beginning and end of our data is Is there a
complex data structure that cries out for a loop?
55Vectors
Vectors (or arrays as theyre known in most other
programming languages) are very well suited to
the idea of loops, and indeed to side effects. So
whats a vector?
56Vectors
Much like a list, vectors store multiple pieces
of data. Unlike a list, a vector is
statically-sized. This means that upon creation
of the vector, we state exactly how many spaces
the vector will have within it. This knowledge
allows random access to any point in our vector.
We know where the beginning of the vector is. We
know where the end of the vector is. We can even
jump to any location in a vector directly! (We
do not need to traverse through a series of cons
cells or structures to get to a location.)
57Vectors
We access particular points in our vectors by
referring to the number representing the
elements position in the vector. This number is
known as an index.
58Vectors
0 1 2
3 4 5
index
Our indices always start with the number 0. So
the first element in our vector has index 0, the
second has index 1, the third has index 2, and so
on. A six element vector will have indices
starting at 0and ending with 5.
59Functions that work with vectors
(vector ltvaluesgt) (make-vector ltsizegt ltoptional
fillgt) (vector-ref ltvectorgt
ltpositiongt) (vector-set! ltvectorgt ltpositiongt
ltnew-valuegt) (vector-length ltvectorgt) (vector?
ltvargt) (build-vector ltsizegt ltfunction to apply to
indexgt)