Title: CS
11321
2CS1321Introduction to Programming
- Georgia Institute of Technology
- College of Computing
- Lecture 18
- October 25, 2001
- Fall Semester
3Todays Menu
- Intermezzo IV Nameless Functions
- Generative Recursion
- Billiard Balls
- Merge Sort
- Mariah
4Last time
In our last lecture, we explored the idea of
going from this
(contains-number? ( 1 2 3 4 5) 6 )
A function which takes in a list of numbers and a
number.
5Last time
To this
(contains? (1 2 3 4 5) 6)
A function which takes in a list of numbers, a
number, and some sort of functionality that acts
on our numbers within the body of the code.
6In our code
(define (contains? in-test in-list value)
(cond ((empty? in-list) false)
(else (cond ((in-test (first in-list) value)
true) (else (contains? in-test
(rest in-list)
value ))))))
Within the actual body of the code, we merely
applied the functionality passed in as an
argument to the first of our list and the value
passed in. This was made possible by exploiting
Schemes simple set of evaluation rules.
7This has implications
The ability to pass functionality as an argument
to another function has certain implications and
raises certain questions. 1) Just what does
(define (f x) ) really mean? 2) If we can
separate a functions actual
functionality from its name, is there a way just
pass function bodies?
8Lambda bodies
Besides being an oh-so recognizable symbol for
DrScheme, the image shown to the left (minus the
nifty coloring) is the greek symbol ? (lambda)
9What is Lambda?
lambada
lambda
Please note the difference.
10Lambda
A lambda expression is nothing more than a
function body without a name.
11?
Lambda, in Scheme, represents a nameless function
body.
(lambda (x y) ( ( x 3) ( - y 2)))
This is a nameless function. It takes in two
arguments (x y), and performs a calculation on
those two arguments (x 3) (y 2).
12? the syntax
Lambda has a very simple syntax
(lambda (parameter1 parameter2 parameter-n)
)
(lambda (in-num) ( in-num 1))
(lambda (in-sym) (cond ((symbol? in-sym
a) true)
(else false)))
13?
All semester long, weve seen that (define) will
bind a symbol to a function body.
Lambda allows us to create a function with no
name.
14Lambda
Scheme already does this. When we type (define
(square x) ( x x)) Scheme sees it
as (define square (lambda (x) ( x x)))
15Example
(define factorial (lambda (num) (if
(zero? num) 1 ( num
(factorial (- num 1))))))
A more traditional example of using no-name
functions.
16Lambda
So lets consider (define square (lambda (x)
( x x)))
The (lambda) part merely means heres a function
that takes in a parameter, called x, and performs
the following operations. This function,
identified by the lambda expression, is defined
as being the symbol square.
17Lambda
So lets consider (define square (lambda (x)
( x x)))
In short, the "lambda" tells Scheme to compile
the function body that follows, and return the
executable result. That is, lambda is like a
function that returns a function.
18Lambda
So lets consider (define square (lambda (x)
( x x)))
The name "lambda" itself comes from something
called "lambda calculus", the mathematical
precursor to functional programming that was
developed by Alonzo Church.
Read more The Advent of the Algorithm, David
Berlinski
19Strategy
So, when lambda is called, Scheme takes in some
code, compiles it, and returns an executable
function.
A compiled function
(Some code)
lambda
20?
Lambda, in Scheme, represents a nameless function
body.
(lambda (x y) ( ( x 3) ( - y 2)))
This example shows a nameless function. It takes
in two arguments (x y), and performs a
calculation on those two arguments,
(x 3) (y 2).
21? the syntax
Lambda has a very simple syntax
(lambda (parameter1 parameter2 parameter-n)
)
(lambda (in-num) ( in-num 1))
(lambda (in-sym) (cond ((symbol? in-sym
a) true)
(else false)))
22? Our original questions
Back to our original questions
1) Just what does (define (f x) )
really mean?
(define (f x) ) creates a function f
with a parameter x that evaluates .
But behind the scenes, we have the following
(define f (lambda (x) ))
23? Our original questions
(define (convertCF in-lon) (cond ((empty?
in-lon) empty) (else (cons ( ( (first
in-lon)1.8) 32) (convertCF (rest
in-lon)))))
(define convertCF (lambda (in-lon)
(cond ((empty? in-lon) empty) (else
(cons ( ( (first in-lon)1.8) 32)
(convertCF (rest in-lon)))))))
THESE ARE EQUIVALENT!
24? Our original questions
2) If we can separate a functions actual
functionality from its name, is there a way just
pass function bodies?
Yep. If youll think back to the last lecture
Here we are stripping away the functionality of
addition from the name and passing it as an
argument.
25? Our original questions
Here I pass in a nameless function body to
my-function.
26? Its not all sun and roses
Before you fall in love with the idea of
lambda-bodies and passing nameless functions,
remember that using functions in this manner has
its draw-backs 1) Less readable code! If you
spontaneously generate a lambda-body to
pass to another function, you include the
entire code for the lambda body in the
code! Clutter! 2) Names are more useful than
you think! Once youve sent a lambda-body
on its way, youve lost your handle on the
function. If you need to use the same
lambda-body in multiple places, youd have
to duplicate the code every time!
27Looking at Recursion
Up until this point, when recursion and recursive
processes were mentioned in class or on an
assignment, we were generally referring to a
particular flavor of recursion structural
recursion. Structural recursion, as defined in
Chapter 25, takes in a complex data type such as
a list or recursive structure and typically
decomposes the data into its components. We then
process those components. If one of those
components is the same data type as our original
data, our function becomes recursive.
28Example from the Template
We decompose a cons cell into its component parts.
(define (process-lon in-lon) (cond ((empty?
in-lon) ) (else (first in-lon)
(process-lon (rest in-lon)))))
29Example from the Template
(define (process-lon in-lon) (cond ((empty?
in-lon) ) (else (first in-lon)
(process-lon (rest in-lon)))))
Theres a clear progression from the beginning of
our list to our termination condition, and this
progression clearly has everything to do with the
data types being supplied.
30Generative Recursion
In Chapter 25, we begin to discuss cases where
the recursion may not be so obvious. In other
words, the recursion may not follow the overall
shape of the data. Each time as we recur, we
might generate new data and new problems that
have to be solved. In the simple cases before,
we put our trust in our data structure. It would
lead us to a solution by its very nature. For
these new cases of recursion, labeled Generative
Recursion, we put our trust in our algorithm, the
underlying thought process that now dictates our
solution.
31Our first example Billiard Balls
For this example, lets say that youre involved
with one of the ongoing projects at the College
of Computing that involves computer vision. The
overall project involves a computer watching
and analyzing the motion of billiard balls on a
pool table during a live game. (This is an
actual project!) The project director has decided
to start you off small before ramping you up to
analyzing video inputs trying to detect color and
motion. He wants you to model the motion of a
billiard ball as it careens around a pool table.
The program stops when the ball reaches a
specified pocket on our simulated table.
32To make things more interesting
Were going to do this example visually using the
draw.ss teachpack provided with DrScheme. Well
write a program that takes as input a ball that
has an initial coordinate and some sort of
initial direction and velocity (represented by a
delta X and a delta Y). Well start off small
(with a pool table thats 100x100) and exit when
the ball reaches the upper right hand corner.
330, 0
100, 0
Lets also set up in our algorithm a little
fudge-factor. This allows us to get close to
the pocket and have the ball fall in, rather than
waiting for the ball to hit the pocket exactly.
100, 100
0,100
The ball will traverse according to a set of
rules, and will bounce off walls or fall into our
corner pocket as appropriate.
34So what well see
Here we see the progression of time
35The Code
As you can imagine, this wont be a simple, one
or two function solution. The actual solution
(coded by David Smith), takes up about 5 to 6
functions. But before we delve into the details,
lets consider one question
36WHERES THE SIMPLE RECURSION?
As we stated earlier, Structural Recursion is
driven by the nature of the data. Lists have
terminating points built into them (the empty
list). Trees have terminating points built into
them (empty, false, stop, etc). Wheres the
stopping point in this data?
37No Guarantees
Note that in no point in time did the problem
statement say The ball will always reach the
upper right pocket. It could be that the
particular angle we impart on a billiard ball
will ALWAYS cause it to miss the particular
pocket were aiming at. (This tends to lose you
a lot of money in the pool halls.) Now we are
forced to trust our algorithm to make handle our
termination condition. Its not necessarily
built in. Ok, lets see this thing in action.
38Code you should look at later
This defines a bunch of constants were going to
use (WIDTH, HEIGHT, DELAY, SIZE, POCKET) and a
function that actually draws the ball on the
screen and makes it go away after a brief delay.
(define WIDTH 100) (define HEIGHT 100) (define
DELAY 0.1) (define SIZE 5) (define POCKET
10) (define (draw-and-clear b) (and
(draw-solid-disk (make-posn (ball-x b) (ball-y
b)) SIZE 'red)
(sleep-for-a-while DELAY) (clear-solid-disk
(make-posn (ball-x b) (ball-y b))
SIZE 'red)))
39A definition we should look at now
(define-struct ball (x y dx dy)) where ball is
a structure (make-ball x y dx dy) such that x,
y, dx, dy are numbers. x y represent our
initial co-ordinate and dx dy represent how
much we should change the position of the ball
when it moves (define the-ball (make-ball 10 20
1 2)) our initial ball
40Lets look at our Main Algorithm
- We will receive a ball
- That ball may or may not be in a pocket. We
should test to see if thats the case. - If its not currently in a pocket, we should draw
the ball and move it. - Once the ball is moved, we should go back to step
1 and start over again.
41Lets look at our Main Algorithm
- (define (draw-iter in-ball)
- That ball may or may not be in a pocket. We
should test to see if thats the case. - If its not currently in a pocket, we should draw
the ball and move it. - Once the ball is moved, we should go back to step
1 and start over again.
42Lets look at our Main Algorithm
- (define (draw-iter in-ball)
- (cond ((in-pocket? in-ball) false) we
need to return something - If its not currently in a pocket, we should draw
the ball and move it. - Once the ball is moved, we should go back to step
1 and start over again.
43Lets look at our Main Algorithm
- (define (draw-iter in-ball)
- (cond ((in-pocket? in-ball) false) we
need to return
something - (else (and we want to draw and
move (draw-and-clear in-ball) - (move-ball in-ball)
- Once the ball is moved, we should go back to step
1 and start over again.
44Lets look at our Main Algorithm
(define (draw-iter in-ball) (cond
((in-pocket? in-ball) false) we need to
return something
(else (and we want to draw and move
(draw-and-clear in-ball)
(draw-iter (move-ball a-ball))))))
45in-pocket?
Is the difference between the current position
and the pocket within our fudge factor
(represented by POCKET)?
(define (in-pocket? b) (and ((ball-x b) WIDTH)) POCKET) ((abs (- (ball-y b) 0)) POCKET)))
46move-ball
The code for move-ball is actually a bit too big
to fit on one screen. Its a very large cond
statement that tests to see if the ball is
either 1) in the middle of the pool table, in
which case we can move by adding the
delta x y to our coordinates. 2) next
to an edge, in which case we need to flip
one or more of the deltas so that the ball
will move in a direction away from the edge. The
complete code will be made available.
47Did we lose you with that last one? Its really
the key to the problem.
48You are here
Lets get back to the code...
49The Big Picture
The key to this exercise is not understanding
graphics. Instead, the point is that we now have
a recursive exercise (moving a balls position)
that may never terminate. We are used to having
recursion that always made progress towards an
end. But here, we see generative
recursion--each recursive call generates a new
need to recur.
50Run it!
billiards.scm
51Another example Merge Sort
We mentioned in Lecture 15 the existence of merge
sort, a sorting algorithm that took in as input a
complex, recursive data type such as a list and
sorted that data by employing a divide and
conquer algorithm. The basic algorithm that
lies behind the merge sort function (on a list of
numbers) is as follows
52Divide and Conquer
- Divide and Conquer cuts the problem in half each
time, but uses the result of both halves - cut the problem in half until the problem is
trivial - solve for both halves
- combine the solutions
53Motivation
Merge sort works on the premise that combining
two sorted lists is fairly fast. (We did this
in previous lectures.) Consider merging (1 2
5 19 27) (3 4 6 20 30)
54Motivation
Merge sort works on the premise that combining
two sorted lists is fairly fast. Consider
merging (1 2 5 19 27) (3 4
6 20 30)
We can compare the car of each list, which we
know to be the smallest from each list. If we
compare the two, we now know which is the
smallest of BOTH lists, since the car of each is
the smallest of each array.
55Motivation
Merge sort works on the premise that combining
two sorted lists is fairly fast. Consider
merging (2 5 19 27) (3
4 6 20 30)
(1)
We then merge by taking the smaller of the two
lists. We never create an inversion for
ourselves, where we accidentally move one item,
and then find we have to move it again.
56Motivation
Merge sort works on the premise that combining
two sorted lists is fairly fast. Consider
merging (5 19 27) (3
4 6 20 30)
(1 2)
We can continue the merge until we have no more
elements from either list So how can we get our
input into two sorted lists so we can take
advantage of this?
57Mergesort
- A divide-and-conquer algorithm
- Divide the unsorted list into 2 halves until the
sub-lists only contain one element - Merge the sub-problem solutions together
- Compare the sub-lists first elements
- Remove the smallest element and put it into the
result list - Continue the process until all elements have been
put into the result list
58How to Remember Merge Sort?
59How To Remember Merge Sort?
(q,t)
Just as Mariah recursively moves her hands into
smaller circles, so too does merge sort
recursively split an array into smaller segments.
We need two such recursions, one for each half of
the split array.
60Merge Sort algorithm
- The function receives as input a list of numbers
- If the list contains more than one element,
divide the list into two lists of equal size
(plus or minus an element). - Perform Merge Sort on the first list
- Perform Merge Sort on the second list
- Merge the results of the two recursive calls
together
Visually
6167
45
23
14
6
33
98
42
6267
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
6367
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
6467
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
6567
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
Merge
6667
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
23
Merge
6767
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
23
98
Merge
6867
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
23
98
6967
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
23
98
Merge
7067
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
14
23
98
Merge
7167
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
45
23
98
14
Merge
7267
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
98
45
14
23
Merge
7367
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
98
14
23
45
14
Merge
7467
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
23
14
98
45
14
23
Merge
7567
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
23
98
45
14
14
23
45
Merge
7667
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
23
98
45
14
23
98
45
14
14
23
45
98
Merge
7767
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
23
98
45
14
14
23
45
98
7867
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
23
98
45
14
14
23
45
98
7967
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
23
98
45
14
Merge
14
23
45
98
8067
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
6
23
98
45
14
Merge
14
23
45
98
8167
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
67
23
98
45
14
6
Merge
14
23
45
98
8267
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
14
23
45
98
8367
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
Merge
14
23
45
98
8467
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
33
23
98
45
14
67
6
Merge
14
23
45
98
8567
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
42
23
98
45
14
67
6
33
Merge
14
23
45
98
8667
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
14
23
45
98
Merge
8767
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
6
42
33
67
6
14
23
45
98
Merge
8867
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
6
33
67
42
6
33
14
23
45
98
Merge
8967
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
6
42
33
67
6
33
42
14
23
45
98
Merge
9067
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
45
98
Merge
9167
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
33
42
67
6
23
45
98
14
Merge
9267
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
42
67
33
23
45
98
14
6
Merge
9367
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
42
67
33
14
45
98
23
6
14
Merge
9467
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
42
67
33
14
23
98
45
6
14
23
Merge
9567
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
67
42
14
23
98
45
6
14
23
33
Merge
9667
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
98
45
6
14
23
33
42
Merge
9767
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
45
98
6
14
23
33
42
45
Merge
9867
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
45
98
6
14
23
33
42
45
67
Merge
9967
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
45
98
6
14
23
33
42
45
67
98
Merge
10067
45
23
14
6
33
98
42
67
45
23
14
6
33
98
42
45
23
14
98
67
6
33
42
23
98
45
14
67
6
33
42
23
98
45
14
67
6
42
33
6
33
42
67
14
23
45
98
6
14
23
33
42
45
67
98
10167
45
23
14
6
33
98
42
6
14
23
33
42
45
67
98
102(video demonstration)
103Translating the Algorithm
- (define (merge-sort in-lon)
- If the list contains more than one element,
divide the list into two lists of equal size
(plus or minus an element). - Perform Merge Sort on the first list
- Perform Merge Sort on the second list
- Merge the results of the two recursive calls
together
104Translating the Algorithm
- (define (merge-sort in-lon)
- (cond ((empty? in-lon) empty)
- (else (local (list into two parts and store them
here) - Perform Merge Sort on the first list
- Perform Merge Sort on the second list
- Merge the results of the two recursive calls
together
105Translating the Algorithm
- (define (merge-sort in-lon)
- (cond ((empty? in-lon) empty)
- (else (local (list into two parts and store them
here) - (merge-sort )
- Perform Merge Sort on the second list
- Merge the results of the two recursive calls
together
106Translating the Algorithm
- (define (merge-sort in-lon)
- (cond ((empty? in-lon) empty)
- (else (local (list into two parts and store them
here) - (merge-sort )
- (merge-sort )
- Merge the results of the two recursive calls
together
107Translating the Algorithm
(define (merge-sort in-lon) (cond ((empty?
in-lon) empty) (else (local
(parts and store them here) (merge
(merge-sort )
(merge-sort ))))))
108Helper functions
Weve written merge in Lecture 15, so we dont
have to worry about that one. What about this
whole division thing? All we have is a list of
numbers, and dividing lists into even parts isnt
going to be a straight forward process.
109One possible approach
- Count the number of elements in the list and
divide it by 2. - Create a function keep that keeps the first half
of the list using the number calculated above. - Create a function skip that skips the first half
of the list using the number calculated above and
returns everything after that point. - Create a function divide that takes the result of
keep and skip and puts that into a wrapper list
so we can just return one item.
110 divide list - list (define (divide lst)
(if (empty? lst) (list empty
empty) (let ((n (/ (count lst) 2)))
(list (keep lst n 0)
(skip lst n 1))))) count
list - number (define (count lst)
(if (empty? lst) 0
( 1 (count (rest lst)))))
keep list n - list of first n items (define
(keep lst n current) (if (or (empty? lst)
( current n)) empty
(cons (first lst) (keep (rest
lst) n ( current 1))))) skip list
n - list of items after the first n
(define (skip lst n current) (cond
(empty? lst) empty ( current
n) (rest lst) else (skip (rest
lst) n ( current
1))))
111Back to our Main Algorithm
(define (merge-sort in-lon) (cond ((empty?
in-lon) empty) (else (local
((define halves (divide in-lon))) (merge
(merge-sort (first halves))
(merge-sort (first (rest halves))))))))
112Applying what we learned
Now, weve created a large set of helper
functions to achieve our main goal. We were only
asked to write a merge-sort algorithm. So what
if we put everything inside a local? That would
be, of course, very acceptable. But what about
this situation?
113Will we always be sorting lists with merge sort?
Nope. Probably not. We could be using the
merge-sort algorithm to sort all kinds of data
types. Each data type will have different code
to divide and merge the actual data, but the
overall algorithm will be the same. So what if
we started passing all the functionality that was
specific to merging two lists (empty?, divide,
merge) and pass that functionality to our
algorithm?