Title: CS1321: Introduction to Programming
1CS1321Introduction to Programming
- Georgia Institute of Technology
- College of Computing
- Module 20
- Generalizing Functions
2Passing functions as parameters!What??
- Passing functions as parameters
- Or
- Now it gets interesting
- Review Adding parameters to generalize
functions - Passing code as values
- Contracts
- The Lambda function
3Last time
At the end of the last module, we started to
explore the idea of similarity in functionality
and how to program for that similarity. Our first
foray into this area of Computer Science dealt
with functions that dealt with the exact same
data types and very similar problem statements
Given a list-of-symbols, write a function
contains-doll? that determines whether or not the
symbol doll is contained in the list.
Given a list-of-symbols, write a function
contains-car? that determines whether or not the
symbol car is contained in the list.
4Similarities in Functions
As we develop more and more functions, one of the
things we start to notice (besides how sore our
fingers become) is just how much many of our
functions resemble each other. Theres always
that one little difference that makes it a
different function, however. So what if we
could get rid of that one little difference?
5It would be relatively trivial for us to write
individual functions that solved the problem
statement
Doll (define (contains-doll? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) doll) true) (else
(contains-doll? (rest in-los)))))))
Car (define (contains-car? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) car) true) (else
(contains-car? (rest in-los)))))))
6But as we see more functions with similar
functionality
Doll (define (contains-doll? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) doll) true)
(else (contains-doll? (rest in-los)))))))
Bob (define (contains-Bob? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) Bob) true)
(else (contains-Bob? (rest in-los)))))))
Truck (define (contains-truck? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) truck) true)
(else (contains-truck? (rest in-los)))))))
Song (define (contains-song? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) song) true)
(else (contains-song? (rest in-los)))))))
Car (define (contains-car? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) car) true)
(else (contains-car? (rest in-los)))))))
Ball (define (contains-ball? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los) ball) true)
(else (contains-ball? (rest in-los)))))))
Orange (define (contains-orange? in-los)
(cond ((empty? in-los) false) (else
(cond ((symbol? (first in-los) orange) true)
(else (contains-orange? (rest in-los)))))))
7Déjà vu!
We come to realize that were writing the same
code over and over again. Heck, we might just
copy/paste our solutions and modifying whats
appropriate. Lets recognize the pattern in
programs to come up with a generic function
8Contains-ltvaluegt?
(define (contains-ltvaluegt? in-los) (cond
((empty? in-los) false) (else (cond
((symbol? (first in-los)
ltvaluegt) true)
(else (contains-ltvaluegt? (rest
in-los)))))))
If it comes down to this every time we write this
function, why dont we just pass a parameter for
the value were looking for?
9Our Solution
(define (contains-symbol? in-los in-symbol)
(cond ((empty? in-los) false) (else
(cond ((symbol? (first in-los)
in-symbol)
true) (else (contains-symbol?
(rest
in-los)
in-symbol))))))
10But wait!
You know, our last solution worked very well for
searching for some random symbol in a list of
symbols. But what about searching for a number
in a list of numbers, or a teaching assistant in
a list of teaching assistants? These are all the
same problem as searching for a symbol in a list
of symbols. Do we have a pattern we can follow?
11Compare and contrast
(define (contains-symbol? in-los in-symbol)
(cond ((empty? in-los) false) (else
(cond ((symbol? (first in-los)
in-symbol)
true) (else (contains-symbol? (rest
in-los)
in-symbol))))))
(define (contains-number? in-lon in-number)
(cond ((empty? in-lon) false) (else
(cond (( (first in-los)
in-number) true) (else
(contains-number? (rest in-lon)
in-number))))))
12Compare and contrast
(define (contains-symbol? in-los in-symbol)
(cond ((empty? in-los) false) (else
(cond ((symbol? (first in-los)
in-symbol)
true) (else (contains-symbol? (rest
in-los)
in-symbol))))))
Our biggest difference seems to lie in this area
in both functions the equality test.
(define (contains-number? in-lon in-number)
(cond ((empty? in-lon) false) (else
(cond (( (first in-los)
in-number) true) (else
(contains-number? (rest in-lon)
in-number))))))
13So whats our pattern?
(define (contains-ltvalue-typegt? in-list-of-type
value) (cond ((empty? in-list-of-type) false)
(else (cond ((ltgeneric equality
testgt
(first in-list-of-type)
value)
true) (else (contains-ltvalue-typegt?
(rest in-list-of-type)
value))))))
14So whats our pattern?
(define (contains-ltvalue-typegt? in-list-of-type
value) (cond ((empty? in-list-of-type) false)
(else (cond ((ltgeneric equality
testgt
(first in-list-of-type)
value)
true) (else (contains-ltvalue-typegt?
(rest in-list-of-type)
value))))))
If we had some way to create a generic equality
test, we could easily just insert it into our
pattern and be fine!
15We could
(cond ((number? value) lthandle numbersgt)
((symbol? value) lthandle symbolsgt)
((list-of-numbers? value) lthandle
list-of-numbersgt) ((list-of-symbols? value)
lthandle list-of-symbolsgt) ((posn? value) lthandle
posngt) ((shape? value) lthandle
shapegt) ((person? value) lthandle persongt) ((ta?
value) lthandle tagt) ((BT? value) lthandle
BTgt) ((BST? value) lthandle BSTgt) ((graph?
value) lthandle graphgt) ((list-of-persons? value)
lthandle list-of-personsgt) ((list-of-tas? value)
lthandle list-of-tasgt) ((fresh-fruit? value)
lthandle fresh-fruitgt) ((Georgia-student? value)
lthand them a mopgt)
Create a function called generic-equality that
took in both the values and their types and used
our various predicates such as number? or symbol?
to set up a massive cond statement to handle
each and every type that we could possibly need
16But
This would be cumbersome to the extreme! Wed
have to add new equality tests every time we
encountered a new type. In addition, what if we
didnt want to just check to see if our list
contained an item EQUAL to a target value? What
if we wanted to test to see if any of the items
in our list were greater than or less than a
given target value? This is still the same
pattern of code!
17As you were leaving
We started discussing a new concept in our
exploration of Computer Science passing
functionality as a parameter.
18And the code
How does this work? Scheme operates on a
relatively simple set of rules. One of those
rules is as follows
19If we see this interpret what follows
as a list of items. If we see this
Interpret what follows as a function call on a
list of Arguments.
(
(
20Examples
The list of , 1, 2 ( 1 2) The function
call on 1 2 ( 1 2) The list of symbol?,
a , b (symbol? a b) The function call
symbol? on a, b (symbol? a b)
21So
If Scheme has determined that it shouldnt
interpret what follows the parenthesis as a list,
it looks for the function definition that matches
the first name that follows the parenthesis.
Have you ever seen
when trying to do the following?
22Scheme is attempting to find a function body
associated with the name a!
23Our example
We can pass function bodies to our new function
and apply them to a set of arguments!
24Our original problem
Lets rename our function to contains?
(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))))))
25Our original problem
Lets rename our function to contains?
(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))))))
Let Scheme handle the problem of applying our
function to our arguments!
26Does it work?
Now we just have to define how we compare two
items of the same type and we have a working
search function.
27Big Picture
To make sure weve understood this example, lets
consider what weve been doing in the course so
far.
28Big Picture The Data
Thus, far, weve done extensive modeling of data.
Familiar diagrams were used to illustrate the
data models.
(cons a empty)
(define-struct book (pages isbn title
author)) (make-book 100 123
DasRepublic Plato)
29The Big Picture Functions
We also defined functions to use this data. We
can visualize what these functions might look
like
(define (area radius) ( radius radius pi))
(define pi 3.14)
3.14
30More Big Picture
In the past, weve called functions with data
(define pi 3.14) (define rad 15) (define (area
radius) ( radius radius pi)) (area rad)
3.14
15
31Thus
(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))))))
32Thus
(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))))))
(contains? symbol? (cons doll empty) doll)
( )
33Another example
Often youll run across a problem that consumes a
data type such as a list and asks you to create a
new list containing a selection of the original
data that meets a certain criteria. We mentioned
two recently
34Write a function lower-than that takes in a
number and a list of numbers and returns a list
of numbers in which every value in our list is
SMALLER than the inputted number.
Write a function higher-than that takes in a
number and a list of numbers and returns a list
of numbers in which every value in our list is
LARGER than the inputted number.
We could alter these two problem statements to
ask for the selection of items equal to a given
number. We could change the problem such that it
deals with symbols, structures, entire lists, etc.
35The Common Thread
When we look at the solutions to the two problem
statements given on the previous slide, we begin
to see the pattern.
36(define (lower-than in-lon in-num) (cond
((empty? in-lon) empty) (else (cond ((lt
(first in-lon) in-num) (cons
(first in-lon) (lower-than (rest in-lon)
in-num))) (else (lower-than (rest in-lon)
in-num))))))
(define (higher-than in-lon in-num) (cond
((empty? in-lon) empty) (else (cond ((gt
(first in-lon) in-num) (cons
(first in-lon) (higher-than (rest
in-lon) in-num))) (else (higher-than (rest
in-lon) in-num))))))
37(define (lower-than in-lon in-num) (cond
((empty? in-lon) empty) (else (cond ((lt
(first in-lon) in-num) (cons
(first in-lon) (lower-than (rest in-lon)
in-num))) (else (lower-than (rest in-lon)
in-num))))))
Our common thread lies in our comparison
operator. In the lower-than function its a lt
comparison between the first item in our list and
the inputted number. In higher-than, its the
gt operator. If we were testing for equal, wed
substitute operator. To handle symbols, we
could insert symbol? where appropriate. For
structures, we could create our own equality
tests
(define (higher-than in-lon in-num) (cond
((empty? in-lon) empty) (else (cond ((gt
(first in-lon) in-num) (cons
(first in-lon) (higher-than (rest
in-lon) in-num))) (else (higher-than (rest
in-lon) in-num))))))
38So if we took away the specific operators in
our problems
(define (threshold in-list in-target) (cond
((empty? in-list) empty) (else (cond
((ltGENERIC TESTgt (first in-list) in-target)
(cons (first in-list)
(threshold (rest in-list) in-target)))
(else (threshold (rest in-list) in-target))))))
This is the generic pattern of our functions.
Wed insert the specific test into the function
to create lower-than or higher-than
39Our threshold function
(define (threshold in-test in-list in-target)
(cond ((empty? in-list) empty) (else (cond
((in-test (first in-list) in-target)
(cons (first in-list)
(threshold in-test
(rest in-list)
in-target))) (else (threshold
in-test (rest in-list) in-target))))))
40Another example mapping
In the last example, we took in a list data
structure and modified the shape of the list by
selecting a portion of its contents for the
result. Lets consider instead the case in which
we keep the shape of the list, but alter the
data contained within the list.
41Sample problem statements
Given a list of numbers representing a
temperature in degrees Celsius, generate a list
of numbers containing the equivalent temperature
in degrees Fahrenheit.
Given a list of TA structures (make-TA name
pay-rate worked) generate a list of symbols
containing the names of the TAs.
Given a list of TA structures (as defined above),
generate a list of numbers containing the amount
of pay received by each TA.
42Our solutions would look likeConverting to
Fahrenheit
(define (convertCF in-lon) (cond ((empty?
in-lon) empty) (else (cons ( ( (first
in-lon) 1.8) 32) (convertCF (rest
in-lon)))))
43Our solutions would look likeExtracting TA Names
(define (extract-name in-loTA) (cond ((empty?
in-loTA) empty) (else (cons (TA-name (first
in-loTA)) (extract-name (rest in-loTA)))))
44Our solutions would look likeCalculating TA
salary
(define (calc-salary in-loTA) (cond ((empty?
in-loTA) empty) (else (cons ( (TA-pay-rate
(first in-loTA)) (TA-worked (first
in-loTA))) (calc-salary (rest in-loTA)))))
45Where is the similarity?
In all three cases, were applying a certain
functionality on each and every item of our list.
We are then putting the result of this
functionality back in a list. This is also known
as mapping a functionality on every item in our
list. The only change we make in each case is
what we do with each value in the list to
calculate the corresponding result. We develop
the following generic function
46Our map function
(define (map functionality in-list) (cond
((empty? in-list) empty) (else (cons
(functionality (first in-list))
(map functionality
(rest in-list))))))
47Map
(define (map functionality in-list) (cond
((empty? in-list) empty) (else (cons
(functionality (first in-list))
(map functionality
(rest in-list))))))
48So how do you denote passing functionality in
your contract?
Passing functions as parameters adds all sorts of
complications to the Contract. We try as best as
possible to show what the expected types of the
values coming in should be, including functions
that are coming into our main function as
parameters. We denote function parameters as
contracts themselves
49 contains? (X Y ? boolean) (listof X) Y ?
boolean
(define (contains? in-test in-list value) )
Breaking it down
(X Y ? boolean) function that consumes two
arguments of unknown type and produces
a boolean (listof X) a shorthand the book
uses for list-of-X Y a value of unknown
type
50 threshold (X Y ? boolean) (listof X) Y ?
(listof Z)
(define (threshold in-test in-list in-target) )
(X Y ? boolean) function that consumes two
arguments of unknown type and produces
a boolean (listof X) a shorthand the book
uses for list-of-X Y a value of unknown
type (listof Z) a list of results of
unknown type
51 map (X ? Y) (listof X) ? (listof Y)
(define (map functionality in-list) )
(X ? Y ) function that consumes an
argument of unknown type and produces
a value of unknown type (listof X) a
shorthand the book uses for
list-of-X (listof Y) a list of results of
unknown type
52Built-in function map
- Contract map (x?y) (listof x) ? listof y
- Purpose consumes a function and a list
applies the function to each element of the
list and creates a list of the results - Examples(map add1 (list 21 15 9)) should
be(list 22 16 10) - (map odd? (list 21 55 100)) should be(list
true true false)
53Built-in function filter
- Contract filter (x?boolean) (listof x) ?
listof x - Purpose applies the function to the list
and returns the list, but omitting all
elements for which the function returns
false. - Examples
- (filter odd? (list 1 2 3)) should
produce(list 1 3) - (filter symbol? (list 1 red sports car 3
marbles)) should produce(list red sports
car)
54Questions?
55(No Transcript)