Recursive Functions Lab: from n! to Fib(n)

Predict and trace recursive processes (linear vs tree recursion), then implement recursive, iterative, and memoized procedures to compare process shape and cost.

0. Predict the Expansion/Contraction Log (Factorial)

Before running anything, **predict** the returned value and the exact `log` list.

Code to reason about:
```python
def fact_log(n, log):
    log.append(f"enter {n}")
    if n == 0:
        log.append("base")
        return 1
    result = n * fact_log(n - 1, log)
    log.append(f"exit {n} -> {result}")
    return result

def run_fact_log():
    log = []
    value = fact_log(3, log)
    return value, log
```

1) What does `run_fact_log()` return?
2) Which happens first: all the `enter ...` messages, or some `exit ...` messages?

After you write your prediction as a comment, run it to check.

  

1. Trace Two Addition Processes (SICP Ex 1.9)

These two procedures both compute `a + b` using only `inc` and `dec`, but they generate different **process shapes**.

Trace by looking at the logged `(a, b)` pairs.

Tasks:
1) Predict the logs for `add_rec_log(4, 5)` and `add_iter_log(4, 5)` (write your prediction as comments).
2) Run the code to check.
3) Explain (in your own words): which one is a **linear recursive process** and which one is an **iterative process**?

```python
def inc(x):
    return x + 1

def dec(x):
    return x - 1
```

  

2. Recursive vs Iterative vs Memoized Recurrence (SICP Ex 1.11)

A function `f` is defined by:

- `f(n) = n` if `n < 3`
- `f(n) = f(n-1) + 2*f(n-2) + 3*f(n-3)` if `n >= 3`

Tasks (in order):

1) **Implement** `f_recursive(n)` using a direct recursive translation.
2) **Implement** `f_iter(n)` that computes the same values but using an **iterative process** (carry state explicitly).
3) **Extend**: implement `f_memo(n, memo=None)` using recursion + memoization (a dictionary cache).

Prediction checkpoint (do this before coding):
- Compute by hand: `f(3)`, `f(4)`, `f(5)`.

Your functions should all agree for the same input.