Practice SICP-style higher-order functions in Python: treat functions as data, reason about closures and composition, and build new behavior by returning and combining functions.
**Predict the output** before running this code.
This is a Python version of SICP Exercise 1.34.
```python
def f(g):
return g(2)
def square(x):
return x * x
h = lambda z: z * (z + 1)
print(f(square))
print(f(h))
print(f(f))
```
1. What are the first two lines that get printed?
2. What happens when we try to evaluate `print(f(f))`?
Choose the best description:
A. Prints `4`, then `6`, then `4` again.
B. Prints `4`, then `6`, then `6` again.
C. Prints `4`, then `6`, then causes a **TypeError** before printing a third line.
D. Causes a **TypeError** on the very first call `f(square)`.
Write down your prediction in a comment, **then** run the code to check.This exercise connects closures (functions that remember values) with function composition.
Consider this code, which is very close to the slide on composition:
```python
def compose(f, g):
def h(x):
return f(g(x))
return h
def make_adder(n):
def adder(x):
return x + n
return adder
square = lambda x: x * x
add1 = make_adder(1)
f = compose(square, add1)
result = f(5)
print(result)
```
1. **Predict** (before running): what will this program print?
2. **Trace the calls** that happen when evaluating `f(5)`:
- Which functions are called, and in what order?
- For each call, what are the argument values (`x`, `n`, etc.)?
- Which frame does each inner function (like `adder` and `h`) *close over*?
Use comments in the starter code to write your trace: show the sequence of calls and how the value `36` is computed step by step.In SICP Exercise 1.43, we define the *n-th repeated application* of a function.
If `f` is a one-argument function and `n` is a positive integer, the n-th repeated application of `f` is the function that applies `f` to its argument **n times**.
Examples:
- If `f(x) = x + 1`, then the n-th repeated application is `x ↦ x + n`.
- If `f(x) = x * x` (square), then the n-th repeated application raises its input to the `2^n` power.
You already saw composition on the slides:
```python
def compose(f, g):
def h(x):
return f(g(x))
return h
```
### Task
1. **Predict** before implementing:
- What should `repeated(lambda x: x + 1, 5)(3)` return?
- What should `repeated(lambda x: x * x, 2)(5)` return?
- What about `repeated(lambda x: x * x, 3)(2)`?
2. **Implement** `repeated(f, n)` so that it returns a new function that applies `f` a total of `n` times.
- You may use recursion **or** a `while`/`for` loop.
- Try to use `compose` from above in your solution, as suggested in SICP.
This exercise is based on **SICP Exercise 1.43** and extends the composition idea from the lecture.