TeachScheme, ReachJava Adelphi University Thursday morning July 15, 2010

Preview:

Citation preview

TeachScheme, ReachJava

Adelphi University

Thursday morning

July 15, 2010

Lists of structsAn employee-list is either• empty, or• (cons employee employee-list)

An employee is…

See employees.scm as starting pointSince an emp-list has a part which is an emp,

function-on-emp-list calls function-on-emp on that part

Lists of structs• Write total-salary which takes in a list of employees & adds up their

salaries

• Write any-over-100k? which takes in a list of employees & tells whether any of them earn over $100,000/year

• Write count-over-100k which takes in a list of employees & tells how many of them earn over $100,000/year

• Write give-10%-raises which takes in a list of employees & returns a similar list in which everybody's salary has increased by 10%

• Write fire-over-100k which takes in a list of employees & returns a list of the ones who don't earn over $100,000/year.

• Write highest-paid, which takes in a non-empty list of employees & returns the highest-paid one. (If there's a tie, return the first of the highest-paid employees.)

Lists of unionsAn animal-list is either• empty, or• (cons animal animal-list)

An animal is either• a dog, or• a fishA dog is… A fish is…

See animals.scm as a starting pointSince a list of animals has a part which is an animal, function-on-

animal-list calls function-on-animal (which in turn calls function-on-dog, function-on-fish, etc.)

Lists of unions

• Write count-tigers, which takes in a list of animals and returns how many of them are tigers

• Write extract-fish, which takes in a list of animals and returns a list of only the fish, in the same order they were in before

• Write lookup-age, which takes in a list of animals and a string, and if there is a dog with that name in the list, returns the dog's age. (If there's more than one, use the first one you find.) If not, return -1.

New topic: Natural numbers

A natural number is either definition by choices!0, or(+ 1 natural-number) definition by (recursive) part!

Examples: 0, (+ 1 0), (+ 1 (+ 1 0)), etc.

We use the names 0, 1, 2, etc. for short.

To get the previous natural-number from a non-zero natural-number n, use (- n 1)

Natural numbers#|

(check-expect (function-on-natural 0) …)

(check-expect (function-on-natural 1) …)

(check-expect (function-on-natural 5) …)

(define (function-on-natural n)(cond [(= n 0) …] [else ; n non-zero natural number ; (- n 1) natural number ; (function-on-natural (- n 1)) … …))

|#

Natural numbers

Example: count-down : natural -> list-of-numbers

(check-expect (count-down 0) (list 0))

(check-expect (count-down 1) (list 1 0))

(check-expect (count-down 5) (list 5 4 3 2 1 0))

Natural numbers

(define (count-down n)(cond [(= n 0) …] [else ; n non-zero natural ; (- n 1) natural ; (count-down (- n 1)) list of nums

…))

Natural numbers

(define (count-down n)(cond [(= n 0) …] [else ; n non-zero natural 5 ; (- n 1) natural 4 ; (count-down (- n 1)) list of nums (list 4 3 2 1 0) ; right answer list of nums (list 5 4 3 2 1 0) …))

Natural numbers

(define (count-down n)(cond [(= n 0) (list 0)] [else ; n non-zero natural 5 ; (- n 1) natural 4 ; (count-down (- n 1)) list of nums (list 4 3 2 1 0) ; should be list of nums (list 5 4 3 2 1 0) (cons n (count-down (- n 1)))))

Exercises

Define a function sqr-table which takes in a natural number and produces a list of posns, each containing a number and its square. The x coordinates should go from the given number down to 1, inclusive.

For example, (sqr-table 4) should be

(list (make-posn 4 16) (make-posn 3 9) (make-posn 2 4) (make-posn 1 1))

Exercises

• Define a function row-of-dots which takes in a natural number and produces a picture of that many radius-10 orange dots side by side.

• Define a function orange-pile which takes in a natural number and produces a picture like

Trees(not in PP, but see HtDP)

Ancestor family trees (binary)

Descendant family trees (n-ary)

two or three mutually-referential data types;write two or three mutually-referential functions

Binary search trees

Expression trees

File hierarchy trees

HTML/XML parse trees

Skip 25 slides (study on your own after workshop)

Family trees, version 1

A person has a string(name), number(birth-year), string(eye-color), mother, and father.

What types are mother and father?

Obviously, "person".

So let's go through the design recipe…

(define-struct person (name birth-year eye-color mother father))

Family trees, version 1

; Contracts for functions that come "for free":

; make-person : string num string person person -> person

; person-name : person -> string

; person-birth-year : person -> number

; person-eye-color : person -> string

; person-mother : person -> person

; person-father : person -> person

Family trees, version 1

; Examples of the data type:(make-person "Fred" 1924 "brown" ? ?)

In order to create a person we need to already have two other persons. Problem!

In addition, in any real family tree, you eventually run out of information and have to say "unknown".

Family trees, version 2

A person has a string(name), number(birth-year), string(eye-color), mother, and father.

What types are mother and father?

"family tree", or "ftree" for short.

An ftree is either unknown or a person.

Family trees, version 2

A person has a string(name), number(birth-year), string(eye-color), mother, and father.

What types are mother and father?

"family tree", or "ftree" for short.

An ftree is either unknown or a person.

Family trees, version 2(define-struct person (name birth-year eye-color mother father)); make-person : string num string ftree ftree -> person; person-name : person -> string; person-birth-year : person -> number; person-eye-color : person -> string; person-mother : person -> ftree; person-father : person -> ftree; person? : anything -> boolean

(define-struct unknown ()); make-unknown : nothing -> unknown; unknown? : anything -> boolean

Family trees, version 2; Examples of data types(define unk (make-unknown)) ; is an unknown, and

therefore an ftree(define fred (make-person "Fred" 1924 "brown" unk unk)

; is a person(define mary (make-person "Mary" 1922 "green" unk unk))(define anne (make-person "Anne" 1944 "blue" mary fred))(define bob (make-person "Bob" 1939 "blue" unk unk))(define phil (make-person "Phil" 1966 "hazel" anne bob))

Family trees, version 2(define (function-on-person p)

; p a person; (person-name p) a string; (person-birth-year p) a number; (person-eye-color p) a string; (person-mother p) an ftree; (function-on-ftree (person-mother p)) whatever; (person-father p) an ftree; (function-on-ftree (person-father p)) whatever)

(define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) (function-on-person ft)]))

Family trees, version 2Or we could collapse the two into one big function:

(define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (function-on-ftree (person-mother ft)) whatever ; (person-father p) an ftree ; (function-on-ftree (person-father ft)) whatever ]))

Writing functions on ftrees & persons

Write a function count-people which takes in an ftree & returns how many persons are in it

; count-people : ftree -> number; Data analysis: already done; Can write either as two mutually recursive

functions, or as one recursive function

Writing functions on ftrees & persons

(check-expect (count-people unk) 0)

(check-expect (count-people fred) 1)

(check-expect (count-people anne) 3)

(check-expect (count-people phil) 5)

Writing functions on ftrees & persons(define (function-on-person p)

; p a person; (person-name p) a string; (person-birth-year p) a number; (person-eye-color p) a string; (person-mother p) an ftree; (function-on-ftree (person-mother p)) whatever; (person-father p) an ftree; (function-on-ftree (person-father p)) whatever)

(define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) (function-on-person ft)]))

Writing functions on ftrees & persons(define (count-people-person p)

; p a person; (count-people (person-mother p)) number; (count-people (person-father p)) number)

(define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) 0 ] [(person? ft) (count-people-person ft)]))

Writing functions on ftrees & persons(define (count-people-person p)

; p a person; (count-people (person-mother p)) number; (count-people (person-father p)) number(+ 1 (count-people (person-mother p)) (count-people (person-father p))))

(define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) 0 ] [(person? ft) (count-people-person ft)]))

Writing functions on ftrees & personsOr, collapsing the two into one big function,…

(define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (function-on-ftree (person-mother ft)) whatever ; (person-father p) an ftree ; (function-on-ftree (person-father ft)) whatever ]))

Writing functions on ftrees & personsOr, collapsing the two into one big function,…

(define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) 0 ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (count-people (person-mother ft)) number ; (person-father p) an ftree ; (count-people (person-father ft)) number ]))

Writing functions on ftrees & personsOr, collapsing the two into one big function,…

(define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) 0 ] [(person? ft) ; (count-people (person-mother ft)) number ; (count-people (person-father ft)) number (+ 1 (count-people (person-mother ft)) (count-people (person-father ft))) ]))

Your turn

• Write a function count-blue-eyed that takes in a ftree and returns the number of blue-eyed people in it

• Write a function count-generations that takes in an ftree and returns the maximum number of generations back it goes (0 for unknown, 1 for a person w/no ancestors, etc.)

• Write a function eye-colors that takes in an ftree and returns a list of all the eye colors (duplicates are OK)

Family trees, version 3

This time we'll work from ancestors to descendants, rather than vice versa.

A person has a string(name), number (birth-year), string(eye-color), and children.

What type is "children"?

A list of persons (possibly empty)

Family trees, version 3

A person has a string(name), number (birth-year), string(eye-color), and a list-of-person (children).

A list-of-person is either

• empty, or

• (cons person list-of-person)

Family trees, version 3

(define-struct person (name birth-year eye-color children))

; make-person : string num string list-of-person -> person

; person-name : person -> string; person-birth-year : person -> num; person-eye-color : person -> string; person-children : person -> list of person

Family trees, version 3

Examples of the new data type…

(define steve (make-person "Steve" 1964 "brown" empty))(define paul (make-person "Paul" 1967 "green" empty))(define jeb (make-person "Jeb" 1981 "brown" empty))(define al (make-person "Al" 1940) "brown" (list steve paul

jeb)); etc. etc.

Family trees, version 3: templates

(define (function-on-person p) ; p a person ; (person-name p) string ; (person-birth-year p) number ; (person-eye-color p) string ; (person-children p) list of

persons ... )

(define (function-on-person-list folx) (cond [(empty? folx) ...] [(cons? folx) ; (first folx) person ; (rest folx) person-list ; (function-on-person (first folx)) whatever ; (function-on-person-list (rest folx)) whatever ... ]))

Family trees, version 3

Note that since a person has a part of type person-list, function-on-person will call function-on-person-list.

Note that since a person-list has a part of type person and a part of type person-list, function-on-person-list will call both function-on-person and function-on-person-list.

This time you can't collapse the two into one big function.

Try writing the corresponding functions for these trees

Your turn

• Write a function count-blue-eyed that takes in a person and returns the number of blue-eyed people descended from that person (including that person)

• Write a function count-generations that takes in a person and returns the maximum number of generations down it goes (1 for a person w/no children, 2 for a person w/children but no grandchildren, etc.)

• Write a function eye-colors that takes in a person and returns a list of all the eye colors (duplicates are OK) of that person and his/her descendants

• Write a function most-kids that takes in a person and returns the largest number of children in any family descended from the person

New topic: Local variables

Recall largest function. Try it on(list 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1)

and on(list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)

Why is one so slow? (depending on how you wrote it)

Use Stepper to see

Local variables

Problem: recomputing recursive call.

Solution: Call once, use result twice.

One way: use helper functionlarger : number number -> number

Another way: define local variable to hold result, then use variable twice.

Local variables

Switch languages to “Intermediate Student”

Syntax rule:

(local [(define var expr) (define var expr) …]expr)

Defines the variables for just long enough to evaluate the final expr.

(local [(define x 3) (define y 5)] (* x y))

; returns 15, but x and y are undefined afterwards

distance with locals

; distance : posn posn -> number

(define (distance here there)

(sqrt (+ (sqr (- (posn-x here) (posn-x there)))

(sqr (- (posn-y here) (posn-y there))))))

distance with locals

; distance : posn posn -> number

(define (distance here there)(local [(define xdiff (- (posn-x here) (posn-x there)))

(define ydiff (- (posn-y here) (posn-y there)))]

(sqrt (+ (sqr xdiff) (sqr ydiff)))))

Actually somewhat longer, but arguably easier to understand because intermediate values have names

largest with locals

(define (largest nums)(cond [(empty? (rest nums)) (first nums)]

[(cons? (rest nums)) (local [(define maxrest (largest (rest nums)))]

(cond [(>= (first nums) maxrest) (first nums)] [else maxrest])

)]))

When to use locals

• to give names to important intermediate values

• to avoid recomputing expensive expressions (especially recursive ones)

• to define things that are only of interest within a particular function(Note: can also define functions & structs inside a local!)

New topic: Abstracting functionsConsider…• add-1-to-each : list-of-numbers -> list-of-numbers• cube-each : list-of-numbers -> list-of-numbers• animal-weights : list-of-animals -> list-of-numbers• convert-grades : list-of-numbers -> list-of-strings• substitute : string string list-of-strings -> list-of-strings• give-10%-raises : list-of-employees -> list-of-employees

All take in a list, do some operation to each element of it, & return a list of the results.

All have almost identical code, differing only in the operation.

Abstracting functionsWhen several functions have similar code, differing in one

thing, turn that thing into a parameter.; do-to-each : operation list -> list

More precisely,; do-to-each : (X->Y) list-of-X -> list-of-Ywhere X and Y are any data types

(Requires Intermediate Student language)Work this out togetherPredefined version is named map

With map, ...

(define (add-1-to-each nums) (map add1 nums))(define (cube-each nums) (map cube nums))(define (animal-weights zoo) (map animal-weight zoo)); where animal-weight is a helper function we write(define (convert-grades nums) (map convert-grade nums)); where convert-grade is a helper function we write(define (give-10%-raises emps) (map give-10%-raise emps))

substitute is a little trickier; we'll come back to this.

Abstracting functionsConsider…• count-elements• count-over-100• count-earning-over-100k• count-tigers

All take in a list and return how many elements meet a certain criterion.

General version:; count-if : test list -> numberMore precisely,; count-if : (X->boolean) list-of-X -> number

ExerciseRe-define• count-elements• count-over-100• count-dogs (in a list of animals)using count-if instead of recursion. You may need to

write some one-line helper functions.

Abstracting functionsConsider…• remove-evens• fire-over-100k• keep-positives• extract-fish

All take in a list and extract from it the elements that meet a certain criterion

General version:; filter : test list -> listMore precisely,; filter : (X->boolean) list-of-X -> list-of-XPredefined, but we could have written it easily

Exercise

Re-define• remove-evens• keep-positives• extract-fishusing filter instead of recursion. You may need to

write some one-line helper functions.

Abstracting functionsConsider…• add-up• multiply-up• total-salary• any-over-100?• all-over-100?• sort

All take in a list and combine its elements, starting from the empty and mixing in one more element at a time. They differ in the answer to the empty case, and in how they combine things.

General form:; foldr : (X Y->Y) Y list-of-X -> Y (predefined, but we could have…)(define (add-up L) (foldr + 0 L))(define (any-over-100? L) (foldr or false L))

Examples and Exercise

; foldr : (X Y->Y) Y list-of-X -> Y(define (add-up L) (foldr + 0 L))(define (any-over-100? L) (foldr or false L))

Re-define• multiply-up• total-salary• any-over-100?• all-over-100?• sortusing foldr instead of recursion. You may need to write some one-line

helper functions.

Functions on the Fly

• Calling a function like map, count-if, filter, or foldr often requires making up a function just to pass in — otherwise useless.

• Example:(define (add-3-to-each nums) (map add3 nums))(define (add3 x) (+ x 3)

• This is silly.

Functions on the Fly: local

• Example:(define (add-3-to-each nums) (local [(define (add3 x) (+ x 3))] (map add3 nums)))

• add3 is "hidden" inside add-3-to-each; doesn't "pollute" rest of world.

Functions on the Fly: lambda

• Switch languages to “Intermediate Student with Lambda”

• Syntax rule:(lambda (params) expr)is a (nameless) function that takes in values for the params and evaluates the expr

• Example:(define (add-3-to-each nums) (map (lambda (x) (+ x 3)) nums)))

• add3 isn't even named.

Functions on the Fly

• More natural example; add-to-each : number list-of-numbers -> list-of-numbers

• Can't do this with a separate function, because we don't know what it's supposed to add until add-to-each is called.

• Easy to do with either local or lambda.

• (define (add-to-each num nums) (local [(define (addit x) (+ x num))] (map addit nums)))

• (define (add-to-each num nums) (map (lambda (x) (+ x num)) nums))

Exercises

• Write a function remove-over that takes a number and a list of numbers, and removes all the numbers over the specified number. No recursion; use a higher-order function instead. Use local or lambda to specify its function argument.

• Re-write substitute using a higher-order function instead of recursion. Use local or lambda to specify its function argument.

• Re-write insert-in-order using a higher-order function instead of recursion. (Tricky!)

Functions returning functions

• Suppose we had lots of occasions to produce a function like add3 or add17.

• Can do it each time with local or lambda, or…

• … automate it with a function! Then…

• (define (add-to-each num nums) (map (make-adder num) nums))

Functions returning functions

; make-adder : num -> (num -> num)

(check-expect ((make-adder 3) 4) 7)

(check-expect ((make-adder -6) 29) 23)

(check-expect (map (make-adder 2) (list 3 4 5)) (list 5 6 7))

(define (make-adder to-add)(local [(define (f x) (+ x to-add))] f))

Functions returning functions

; make-adder : num -> (num -> num)

(check-expect ((make-adder 3) 4) 7)

(check-expect ((make-adder -6) 29) 23)

(check-expect (map (make-adder 2) (list 3 4 5)) (list 5 6 7))

(define (make-adder to-add)(lambda (x) (+ x to-add)))

Extra credit exercises

• Define a function twice that takes in a function f:X->X and returns the function g(x) = f(f(x)). For example,(define add2 (twice add1))(define 4th-root (twice sqrt))

• Define a function iterate that takes in a function f:X->X and a natural number n and returns the function f(n), i.e. f composed with itself n times. For example,(define add5 (iterate add1 5))

Abstracting functions

I try to introduce this stuff in Scheme because

• it's a powerful programming tool in any language

• it's enormously easier in Scheme than in C++ or Java

• it blows people's minds

I/O,sequential programming,

and mutation

Not covered this week; see Picturing Programs

Recommended