Environment Diagrams Lab

Practice predicting, tracing, and building programs using Python’s environment model: frames, name lookup, and closures with local state.

0. Exit Ticket Prediction: Closure vs Global Name

**Predict the output** (without running) using the environment model.

```python
def make_adder(n):
    def adder(x):
        return x + n
    return adder

add_three = make_adder(3)

n = 100
print(add_three(10))
print(n)
```

1) What does it print?
2) In one sentence: which `n` does `adder` use, and why?

  

1. Trace Call Frames: Recursive vs Loop Factorial (SICP Ex 3.9-inspired)

This exercise is about **how many frames exist over time**.

Consider these two factorial implementations:

```python
def factorial_rec(n):
    if n == 0:
        return 1
    return n * factorial_rec(n - 1)

def factorial_loop(n):
    product = 1
    k = 1
    while k <= n:
        product *= k
        k += 1
    return product
```

**Trace prompts (write answers as comments):**

A) For `factorial_rec(4)`, list each call frame created (in order), and the `n` bound in that frame.

B) For `factorial_rec(4)`, list the return values as the recursion unwinds.

C) For `factorial_loop(4)`, how many *function call frames* are created total for the computation (not counting `while` loop “iterations” as frames)? Explain briefly.

  

2. Build and Extend a Message-Passing Account (SICP Ex 3.11-inspired)

Implement a **message-passing** bank account using closures.

You will write `make_account(balance)` that returns a `dispatch` function.

- `dispatch('withdraw')` should return a function that takes `amount` and withdraws if possible.
- `dispatch('deposit')` should return a function that takes `amount` and deposits.

Then **extend** it:
- `dispatch('balance')` should return a *zero-argument* function that returns the current balance.

Finally, **predict** (before running) what the prints produce:

```python
acc = make_account(50)
print((acc('deposit'))(40))   # ?
print((acc('withdraw'))(60))  # ?
print((acc('balance'))())     # ?

acc2 = make_account(100)
print((acc2('withdraw'))(10)) # ?
print((acc('balance'))())     # ?
```

Your implementation should keep `acc` and `acc2` state **distinct** (two different enclosed frames).