Lesson 13 of 15

Closures and Scoping

User-Defined Functions and Closures

The most powerful feature of a language is user-defined functions. We'll add:

fn square(x) = x * x;

What is a Closure?

A closure captures the environment where it was defined. This means a function can "remember" variables from its surrounding scope:

let a = 10;
fn addA(x) = x + a;
print addA(5);    // prints 15

Implementation

A function value stores: { type: "Function", params: [...], body: <expr>, env: {...} }

When calling a user-defined function:

  1. Create a new environment that extends the closure's captured environment
  2. Bind the arguments to parameter names
  3. Evaluate the body in this new environment
if (node.type === "FnStatement") {
    env[node.name] = {
        type: "Function",
        params: node.params,
        body: node.body,
        env: { ...env }  // capture current environment
    };
}

// In CallExpr evaluation:
const fn = env[node.name];
if (fn && fn.type === "Function") {
    const newEnv = { ...fn.env };
    fn.params.forEach((p, i) => { newEnv[p] = args[i]; });
    return evaluate(fn.body, newEnv);
}

Your Task

Add fn name(params) = body; syntax. Functions should capture their enclosing environment (closures).

Node.js loading...
Loading...
Click "Run" to execute your code.