Skip to main content

Abstraction and Interpretation: Worked Examples

Work through each trace before reading the explanation. Then solve the transfer task without the page open.

Example 1: A closure carries its defining environment​

Define makeAdder(x) to return a function y -> x+y. Let add3=makeAdder(3), then call add3(4) in a context where another variable x equals 100.

Lexical scope yields 7: the closure stores its code and a reference to the environment binding x to 3. Looking up x in the caller instead yields 104 and implements a different scoping rule. A function's code alone does not represent a closure.

Example 2: Conditionals cannot eagerly evaluate every branch​

Consider if(true,1,divide(1,0)) in a small language. An evaluator that first evaluates all call arguments raises division by zero before choosing a branch.

Treat conditional evaluation as a special form: evaluate the condition, then only the chosen branch. Ordinary eager function application cannot directly implement this behavior without delaying branch computations, for example as thunks. Evaluation order is part of language semantics.

Transfer and self-check​

Create add3 and add10 from the same factory. What should add3(2) and add10(2) return? Check: 5 and 12; explain why their captured bindings remain distinct.

Evidence to keep​

Save your first attempt, corrected reasoning, and transfer result as checkpoint evidence. A matching final answer without an explanation is insufficient. Continue with the guided lab and use the reading guide to repair a specific gap.