- What are the steps to evaluating def statements, assignments statements, and call expressions?
- What is a recursive function. Why does a recursive function need a base case?
How many call frames are opened if you call
decrease_to_one(decrement, 5)? What about
The initial call to
decrease_to_onewill open a frame. In the body of
fis called until
1. So the question is, how many times does it take to reach
fon it? For
decrease_to_one(decrement, 5), it'll take 4 calls to
f(2)), and for
decrease_to_one(half, 8), it'll take 3 calls to
f(2)). Each of these calls requires a new frame, so the answers are 5 and 4.
Fill in the blanks below so that the output is as follows.
First, we see that the return value of
foo(____________)(____________)is passed as an argument to
bazand will be bound to the parameter
z. Notice that
zis being called with no arguments in the body of
baz. That means that the entire expression
foo(____________)(____________)must return a zero-argument function.
Now let's analyze the call expression itself. First, we evaluate the operator:
foo(____________). This operator is itself a function call, and we know it must return a function. Well, that's already taken care of, because
foo's return value is always the function
barregardless of the input. So what should we pass through to it? Notice that
xis called on the string
"Higher order functions " + y. That must mean that our argument is a function, more specifically, a one-argument lambda function. So then we have this: Since I've named the lambda's parameter
x, the entire string
"Higher order functions " + ywill be bound to
xwhen we execute this lambda. Keep in mind now that
lambda x: ???will be bound to the parameter
Let's skip the lambda's body for now and move on what to put in the second set of parentheses. We've established that
foo(lambda x: ???)will return
bar, so essentially
foo(lambda x: ???)(____________)becomes
bar(_________). Figuring out what to pass through to
baris easy. We see that the parameter
ywill be added to the string
"Higher order functions ". This is the only place in our code where we can concatenate strings, so
ymust be bound to
"are awesome". So now all that's left is to write the body of the lambda:
Earlier I said that the entire expression above must return a zero-argument function that will be bound to
baz. How can we make that happen? Well the return value of that whole expression is actually just the return value of
foo(lambda x: ???)(____________)is basically
barreturns the value of
"Higher order functions " + y! Recall that
xis bound to the lambda function we already wrote in. Thus, for
barto return a zero-arg function, our lambda must return a zero-arg function:
Let's regroup and go over what our "bindings" are so far.
xis bound to
lambda x: lambda: ???.
zis bound to that inner lambda,
lambda: ???. The parameter
xto our first lambda will be bound to the string we want to print.
Now, to figure out what that inner lambda should return, we must turn back to
baz. Our desired action is to print the string that is bound to
xin the first lambda.
baztakes care of the printing for us; it prints the return value of
z(). That means that our inner zero-argument lambda must return the string we want to print, which is bound to the parameter
xof the outer lambda function. This completes the solution:
Important note #1: Throughout the explanation I said that certain variables are bound to
lambda ... : .... I do not that the variables are literally bound to those lambda expressions; it was simply a clean way to refer to certain functions. Remember than lambda expressions are just unevaluated expressions just like
2+4. What I mean is that the variable is bound to the function object that that lambda expression creates.
Important note #2: I don't expect you to read through this lengthy explanation and totally understand everything that's going on. For that reason I highly recommend drawing out the environment diagram. You can find the solution to the environment diagram here.