six compound procedures and higher-order procedures
Post on 19-Dec-2015
220 views
TRANSCRIPT
six
compound proceduresand higher-order procedures
A box figure
► [group [box 400 400]
[translate [point 100 100]
[box 70 70]]
[translate [point 100 −100]
[box 70 70]]
[translate [point −100 −100]
[box 70 70]]
[translate [point −100 100]
[box 70 70]]]
Simplifying with names
► [define frame [box 400 400]]
► [define little [box 70 70]]
► [group frame
[translate [point 100 100]
little]
[translate [point 100 −100]
little]
[translate [point −100 −100]
little]
[translate [point −100 100]
little]]
What’s wrong with this?
Defining little and frame saves us a little bit of work, but …
What we really want to do is to name the whole pattern of making shifted boxes…
We need abstraction
What we want to be able to say
► [define frame [box 400 400]]
► [group frame [shifted 100 100] [shifted 100 −100] [shifted −100 −100] [shifted −100 100]]
What kind of a thing is shifted?
Well, it takes inputs It returns an output It must be a procedure…
In fact, we even know what it should do It should make a point from its two arguments Make a box Translate the box by the point And return it
Compound procedures
[arg1 arg2 … argn → exp]
Procedures are just another data object You can construct new procedures from old using the → symbol When called, the procedure
Sets the local names arg1 arg2 … argn to the arguments passed to the procedure
Computes the value of exp using the values of the arguments Returns the value of exp
Note: you type the → symbol by first typing – and then >
Defining shifted
► [define shifted [x y → [translate [point x y] little]]]
► [group frame [shifted 100 100] [shifted 100 −100] [shifted −100 −100] [shifted −100 100]]
A boring example
Square is a compound procedure built from ×
Polynomial is a compound procedure built from ×, +, and square
Notice they both use the name n for their argument But it’s okay because
they’re local names
► [define square [n → [× n n]]]► [square 2]4► [square 58.7]3445.69► [define polynomial [n → [+ [square n] [× n 2] 4]]]► [polynomial 32]1092►
A more interesting procedure
We haven’t taught you enough at this point to understand how iterated-group works
You’ll understand in a few weeks For the moment, just copy it from
this slide and use it
But the thing we do want you to understand is that
You give it a procedure that makes pictures
And a number of times to call it And it gives you a group of all the
results of calling the procedure with the arguments 0, 1, 2, etc.
► [define iterated-group [proc count → [apply group [up-to count proc]]]]
Using iterated-group
[iterated-group[n → [line [point [× n 20] 0] [point [× n 20] 300]]]10]
Using iterated-group
[iterated-group[n → [ink [pen 'black n] [line [point [× n 20] 0] [point [× n 20] 300]]]]21]
Using iterated-group
► [iterated-group [n → [translate [point [× n 20] [× n 20]] [box 10 10]]]
5]
►
Using iterated-group
► [iterated-group [n → [translate [point 0 [× n 10]] [box 10 10]]]
5]
►
Using iterated-group
► [iterated-group [n → [translate [point [× n 10] [× [sin [ ⁄ n 2]] 30]] [box 10 10]]] 20]
►
What about this one?
► [iterated-group [m → [iterated-group [n → [translate [point [× m 10] [× n 10]] [box 10 10]]]
5] 5]
?►
What about this one?
► [iterated-group [m → [iterated-group [n → [translate [point [× m 10] [× n 10]] [box 10 10]]]
5] 5]
Makes one block
What about this one?
► [iterated-group [m → [iterated-group [n → [translate [point [× m 10] [× n 10]] [box 10 10]]]
5] 5]
Makes one block Iterates it vertically to make a stack of blocks
What about this one?
► [iterated-group [m → [iterated-group [n → [translate [point [× m 10] [× n 10]] [box 10 10]]]
5] 5]
Makes one block Iterates it vertically to make a stack of blocks Iterates the whole stack horizontally
What about this one?
► [iterated-group [m → [iterated-group [n → [translate [point [× m 10] [× n 10]] [box 10 10]]]
5] 5]
►
What about this one?
► [iterated-group [n → [rotate [× 10 n] [translate [point n 0] [paint [color [× n 10] [− 256 [× n 10]] 0] [box 100 50]]]]] 25]
What about this one?
► [iterated-group [n → [rotate [× 10 n] [translate [point n 0] [paint [color [× n 10] [− 256 [× n 10]] 0] [box 100 50]]]]] 25]
►
Making a variant of iterated-group
Iterated-group always counts from 0 to count-1 by 1
What if we wanted different ranges? different steps?
[define iterate-in-range[proc start end count → ???]]
Making a variant of iterated-group
We want to write something that acts just like iterated-group, but Counts from start to end
instead of 0 to count-1 Does it in count steps
How do we write something like that?
[define iterate-in-range[proc start end count → ???]]
Making a variant of iterated-group
How about using iterated-group?
Constructive laziness: Get as much mileage
as you can from your existing tools
[define iterate-in-range[proc start end count → [iterated-group ??? ???]]]
Making a variant of iterated-group
Okay, so what arguments do we pass to iterated group?
[define iterate-in-range[proc start end count → [iterated-group ??? ???]]]
Making a variant of iterated-group
The easy one is the count We know that we still
want to run count times
So we just pass the count parameter on
[define iterate-in-range[proc start end count → [iterated-group ??? count]]]
Making a variant of iterated-group
The procedure argument is harder
[define iterate-in-range[proc start end count → [iterated-group ??? count]]]
Making a variant of iterated-group
The procedure argument is harder
We could just pass proc on But then it gets called with
numbers between 0 and count …
… and we want it to get called with numbers between start and end
[define iterate-in-range[proc start end count → [iterated-group proc count]]]
Making a variant of iterated-group
The procedure argument is harder
We could just pass proc on [Can’t]
But sooner or later, we do need to call proc The question is what we
pass to it Can’t be n because n goes
from 0 to count…
[define iterate-in-range[proc start end count → [iterated-group [n → [proc ???]] count]]]
Making a variant of iterated-group
We need an expression that converts n
(a number from 0 to count) Into a number from start to
end
[define iterate-in-range[proc start end count → [iterated-group [n → [proc ???]] count]]]
Making a variant of iterated-group
We need an expression that converts n
(a number from 0 to count) Into a number from start to
end
Here’s a trick: Add start
Now it at least starts at start
[define iterate-in-range[proc start end count → [iterated-group [n → [proc [+ start
n]]] count]]]
Making a variant of iterated-group
We need an expression that converts n
(a number from 0 to count) Into a number from start to
end
Here’s a trick: Add start
Now it at least starts at start
And multiply n by a fudge factor to make it work out to end when n=count
[define iterate-in-range[proc start end count → [iterated-group [n → [proc [+ start
[× n ???]]]] count]]]
Making a variant of iterated-group
We need an expression that converts n
(a number from 0 to count) Into a number from start to
end
Here’s a trick: Add start
Now it at least starts at start And multiply n by a fudge
factor to make it work out to end when n=count
It’s not obvious, but the right fudge factor turns out to be:
(end-start)/count
[define iterate-in-range[proc start end count → [iterated-group [n → [proc [+ start
[× n [ ∕ [- end start]
count]]]]] count]]]
Common errrors
See if you can identify the bugs in this code
Code:[iterated-group [box 10 10] 10]
Error message:Argument Type Exception
Getting the types wrong
Code:[iterated-group [box 10 10] 10]
Iterated-group needs a procedure as its first argument
Getting the types wrong
Code:[iterated-group [n → [box 10 10]] 10]
This runs, but it produces 10 boxes of the same size in the same position, piled on top of one another
Code:[iterated-group [n → [translate [point [n] 0] [box 10 10]]] 5]
Error message:Tried to call something that wasn’t a procedure
Don’t write all your code on one line
Code:[iterated-group [n → [translate [point [n] 0] [box 10 10]]] 5]
Error message:Tried to call something that wasn’t a procedure
Don’t write all your code on one line
Code:[iterated-group [n → [translate [point [n] 0] [box 10 10]]] 5]
Error message:Tried to call something that wasn’t a procedure
Gratuitous bracketing
Code:[iterated-group [n → [translate [point [n] 0] [box 10 10]]] 5]
Adding brackets means “call this as a procedure” But it’s not a procedure
Code:[iterated-group [n → [translate [point 0 n [box 10 10]]]] 10]
Error message:Wrong number of arguments
Missing bracket
Code:[iterated-group [n → [translate [point 0 n] [box 10 10]]]] 10]
Forgetting the bracket at the end of the point call makes the box an argument to point
Missing bracket
Code:[iterated-group [n → [translate [point 0 n] [box 10 10]]] 10]
Fixing the bracketing also fixes the indenting Notice that box and point are now indented
together Meaning they are both arguments to translate
Code:[iterated-group [n → [translate [point n × 7 0] [box 10 10]]] 10]
Error message:Wrong number of arguments
Brackets missing entirely
Code:[iterated-group [n → [translate [point [n × 7] 0] [box 10 10]]] 10]
Error message:Attempt to call something that isn’t a procedure
Brackets missing entirely
Code:[iterated-group [n → [translate [point [× n 7] 0] [box 10 10]]] 10]
The procedure always has to come first
Code:[iterated-group [n → [translate [rotate 30 [box 10 10]] [point n 10]]] 10]
Error message:Argument type exception
Arguments out of order
Code:[iterated-group [n → [translate [point n 10] [rotate 30 [box 10 10]]]] 10]
Conditionals: the if operator
[if test consequent alternative] If test is true,
Then evaluate and return consequent
Otherwise, evaluate and return alternative
Some useful tests [= a b]
Checks if a and b are the same [> a b], [≤ a b], etc.
Compares numbers [and test1 test2 … testn]
[or test1 test2 … testn][not test]
Combines tests into more complicated tests
► [define abs [n → [if [> n 0] n
[- n]]]]<Procedure abs>► [abs 5]5► [abs -5]5►
Boolean objects
Everything in Meta is an expression, And (almost) all expressions have values,
So then what kind of value is [= a b] ?
Answer: true or false
The system includes two magic data objects, true and false, which are used to represent the answers to tests
Final rules of computation
If it’s a word (i.e. a name) Look up its value in the dictionary Return (output) it
If it’s a constant It’s its own value Return it
If it says [define name value] Find the value of value Update the dictionary entry for name
If it looks like: [name … name → expression]
Make a procedure Whose arguments have the specified name And whose return value is expression
If it says [if test consequent alternative] Compute the value of test If it’s the magic value true, compute and return the
value of consequent Otherwise, compute and return the value of
alternative
If it says [with name = value … expression]
Find the values of all the value expresions Update their respective names in the dictionary Compute expression using the revised dictionary Set the dictionary back
If it otherwise has brackets (i.e. it looks like “[a b c …]”)
Find the values of subexpressions Call first one with others as inputs Return its output