...
A function definition introduces a new local scope – - the parameters are defined within the body.
...
(define (parameters...)
body)
...
A local definition
introduces a new local scope – - the names in the definitions are defined
within both within the bodies of the definitions and within the
local's body.
...
(local definitions...
body)
...
Wiki Markup |
---|
Note that the use of square brackets |
. The brackets help set off the definitions |
a little more clearly for readability. |
...
...
In order to uselocaland use local and the other features about
to be introduced in class, you need to set the DrScheme language level to
"Intermediate".
...
Exercises
Finding the maximum element of a list
...
.
Here are two easy ways to misuselocal:
Wiki Markup |
---|
; max-of-list: non-empty-list \-> number |
(define (max-of-list a-nelon) |
(local [(define max-rest (max-of-list (rest a-nelon))) |
(cond |(define max-rest (max-of-list (rest a-nelon)))]
(cond [(empty? (rest a-nelon)) (first a-nelon)|(empty? (rest a-nelon)) (first a-nelon) |
]
\[else (cond [(< (first a-nelon) max-rest) max-rest |
]
[else (first a-nelon)|else (first a-nelon)])\]))) |
Question
...
Make sure you don't put alocaltoo early in your code.
Wiki Markup |
---|
; max-of-list: non-empty-list \-> number |
(define (max-of-list a-nelon) |
(cond [(empty? (rest a-nelon)) (first a-nelon) |
[else (local |(empty? (rest a-nelon)) (first a-nelon)]
\[else (local \[(define max-rest (max-of-list (rest a-nelon))) |
(define first-smaller? (< (first a-nelon) max-rest))\] |
(cond [first-smaller? max-rest |
else (first |first-smaller? max-rest]
[else (first a-nelon)|else (first a-nelon)]))\])) |
This isn't wrong, but the local definition offirst-smaller?
is unnecessary. Since the comparison is only used once,
this is not a case of code reuse or recomputation.
It provides a name to a part of the computation,
but whether that improves clarity in this case is a judgement call.
...
(define x 5)
(define x^ 7)
x^
Example:
⇒
(define x 5)
(define y x)
(define z (+ x y))
(define x^ 7)
(define y^ x^)
(+ x^ y^ z)
...
As an equivalent way of looking at things, we can look at the original code
and askwhich definitioncorresponds to each placeholder use.
The answer is simple – - it is always the closest (in terms of nestedness)
enclosing
...
(define w 1)
(define x 3)
(define y 5)
Wiki Markup |
---|
(local \[(define w 2) |
(+ w x y)
(test 8 3)
(test x w)
(test w x)
Here is an example of mutually recursive functions following the
template for natural numbers.
It is motivated by the observation "a positive number n
is even if n-1 is odd, a positive number n is odd if n-1 is even,
and 0 is even."
Wiki Markup |
---|
(local \[; my-odd?: natnum \--> boolean |
false false|(zero? n) false]
[(positive? n) (my-even? (sub1 n))|(positive? n) (my-even? (sub1 n))])) |
; my-even?: natnum --> boolean
(define (my-even? n)
(cond (zero? n) true
(positive? n) (my-odd? (sub1 n))))]
...
(define x 1)
(define y 2)
(local \[(define (g x) (\+ x y)) |
Wiki Markup |
---|
(local \[(define x 30) |
(define (g x) (\* x y))\] |
(g 20)
(f 20)
...
As a reminder, we've discussedfilter.
Starting from several examples using specific predicates,
we noticed a great deal of similarity.
By abstracting away that similarity into a function parameter,
we obtained the following definition:
Wiki Markup |
---|
; filter : (X \->boolean) [X] \-> [X] ; Purpose: Returns a list like the one given, except with those ; elements not passing the given predicate test removed. (define (filter keep? l) (cond [(empty? l) empty|(empty? l) empty] \[(cons? l) (cond [(keep? (first l)) (cons (first l) (filter keep? (restl))) |
else(filter keep? |(keep? (first l)) (cons (first l) (filter keep? (restl)))] |
)) [else(filter keep? (restl))|else(filter keep? (restl))])\])) |
As an alternative, we could note that the above definition repeats
the code
(filter keep? ...As an alternative, we could note that the above definition repeats
the code
(filter keep? …)
.
I.e.,keep?
is an invariant argument.
We could choose to avoid that, as follows:
Wiki Markup |
---|
; filter : (X \->boolean) [X] \-> [X] ; Returns a list like the one given, except with |
those ; elements not passing the given predicate test removed. (define (filter keep? l) (local [(define (filter-helper l) (cond (empty? l) empty [(cons? l) (cond (keep? (first l)) (cons (first l) (filter-helper (restl))) else(filter-helper (restl)))]))] (filter-helper those ; elements not passing the given predicate test removed. (define (filter keep? l) (local \[(define (filter-helper l) (cond [(empty? l) empty|(empty? l) empty] \[(cons? l) (cond [(keep? (first l)) (cons (first l) (filter-helper (restl)))|(keep? (first l)) (cons (first l) (filter-helper (restl)))] [else(filter-helper (restl))|else(filter-helper (restl))])\]))\] (filter-helper l))) |
filterexercises
...
(map f (list x<sub>1</sub> … ... x<sub>n</sub>)) = (list (f x<sub>1</sub>) … ... (f x<sub>n</sub>))
...
(foldr f base (list x<sub>1</sub> x<sub>2</sub> … ... x<sub>n</sub>)) = (f x<sub>1</sub> (f x<sub>2</sub> … ... (f x<sub>n</sub> base)))
Many functions we've written fit this pattern, although
this might not be obvious at first.
...
(andmap f (list x<sub>1</sub> … ... x<sub>n</sub>)) = (and (f x<sub>1</sub>) … ... (f x<sub>n</sub>)) (ormap f (list x<sub>1</sub> … ... x<sub>n</sub>)) = (or (f x<sub>1</sub>) … ... (f x<sub>n</sub>)) (build-list n f) = (list (f 0) … ... (f (sub1 n)))
The following is a quick summary of the abstract functions mentioned
in this lab:
filter
– -
selects some elements from a list
...
map
-
applies a function to each list element
andmap
/ormap
– -
applies a function to each list element and combines the resulting booleans
...
:
(list <VAR>n</VAR>-(<VAR>i</VAR>-1) … ... <VAR>n</VAR>-1 <VAR>n</VAR>)More concretely, e.g.,
(nums-upto-help 5 0) ⇒ empty (nums-upto-help 5 2) ⇒ (list 4 5) (nums-upto-help 5 5) ⇒ (list 1 2 3 4 5) (nums-upto-help 6 5) ⇒ (list 2 3 4 5 6) (nums-upto-help 7 5) ⇒ (list 3 4 5 6 7)
...
Defineandmap, which computes
whether all elements in a list of booleans are true:
(andmap f (list x<sub>1</sub> … ... x<sub>n</sub>)) = (and (f x<sub>1</sub>) … ... (f x<sub>n</sub>))First, define it recursively following the list template, then
define it using
foldr
andmap
,
then using onlyfoldr
.
...
(foldl f base (list x<sub>1</sub> x<sub>2</sub> … ... x<sub>n</sub>)) = (f x<sub>n</sub> … ... (f x<sub>2</sub> (f x<sub>1</sub> base))…...)
foldlexercises
...