Skip to content

Education & Prototyping

Grapa's dynamic grammar and meta-programming are ideal for rapid prototyping and teaching programming concepts.

Key Features for Education:

  • Interactive Learning: Immediate feedback and experimentation
  • Visual Debugging: See AST and execution flow
  • Language Design: Create custom languages and DSLs
  • Algorithm Visualization: Step-through execution

Example: Teaching Recursion

/* Visualize recursive function execution */
factorial_with_trace = op(n, depth) {
    indent = "  ".repeat(depth);
    (indent + "factorial(" + n.str() + ")").echo();
    if (n <= 1) {
        (indent + "return 1").echo();
        1;
    } else {
        result = n * factorial_with_trace(n - 1, depth + 1);
        (indent + "return " + n.str() + " * " + (n - 1).str() + "! = " + result.str()).echo();
        result;
    };
};

/* Example: Calculate 4! with trace */
"Calculating 4! with execution trace:".echo();
result = factorial_with_trace(4, 0);
("Final result: " + result.str()).echo();

Example: Custom DSL for Data Processing

/* Define a simple data processing language */
data_dsl_grammar = {
    "pipeline": "command*",
    "command": "filter_command | map_command | reduce_command",
    "filter_command": "'filter' condition",
    "map_command": "'map' expression", 
    "reduce_command": "'reduce' expression 'with' initial_value",
    "condition": "field operator value",
    "expression": "field | function_call",
    "operator": "'==' | '!=' | '>' | '<' | '>=' | '<='"
};

/* Example DSL usage */
dsl_script = "
filter age > 18
map salary * 1.1
reduce sum with 0
";

/* Execute the DSL */
execute_dsl = op(script, data) {
    ast = $rule().parse(script, data_dsl_grammar);
    $rule().execute(ast, data);
};

Example: Algorithm Visualization

/* Visualize sorting algorithms */
bubble_sort_with_trace = op(array) {
    n = array.len();
    trace = [];

    i = 0;
    while (i < n - 1) {
        j = 0;
        while (j < n - i - 1) {
            /* Show current state */
            current_state = array.copy();
            trace += {
                "step": "Compare " + array.get(j).str() + " and " + array.get(j + 1).str(),
                "array": current_state,
                "comparing": [j, j + 1]
            };

            /* Swap if needed */
            if (array.get(j) > array.get(j + 1)) {
                temp = array.get(j);
                array.set(j, array.get(j + 1));
                array.set(j + 1, temp);

                trace += {
                    "step": "Swap " + array.get(j).str() + " and " + array.get(j + 1).str(),
                    "array": array.copy(),
                    "swapped": [j, j + 1]
                };
            };
            j += 1;
        };
        i += 1;
    };

    {"sorted_array": array, "trace": trace};
};

/* Example usage */
data = [64, 34, 25, 12, 22, 11, 90];
result = bubble_sort_with_trace(data);

"Bubble Sort Visualization:".echo();
result.get("trace").map(op(step) {
    (step.get("step") + ": " + step.get("array").join(", ")).echo();
});

("Final sorted array: " + result.get("sorted_array").join(", ")).echo();

Example: Interactive Language Learning

/* Interactive calculator with step-by-step evaluation */
interactive_calculator = op(expression) {
    /* Parse the expression */
    ast = $rule().parse(expression, {
        "expression": "term (( '+' | '-' ) term)*",
        "term": "factor (( '*' | '/' ) factor)*",
        "factor": "number | '(' expression ')'",
        "number": "[0-9]+"
    });

    /* Evaluate with trace */
    evaluate_with_trace = op(node, depth) {
        indent = "  ".repeat(depth);

        if (node.type() == "number") {
            value = node.get("value").int();
            (indent + "Number: " + value.str()).echo();
            value;
        } else if (node.type() == "expression") {
            (indent + "Expression: " + node.get("text")).echo();

            if (node.get("terms").len() == 1) {
                evaluate_with_trace(node.get("terms").get(0), depth + 1);
            } else {
                left = evaluate_with_trace(node.get("terms").get(0), depth + 1);
                operator = node.get("operators").get(0);
                right = evaluate_with_trace(node.get("terms").get(1), depth + 1);

                result = 0;
                if (operator == "+") {
                    result = left + right;
                } else if (operator == "-") {
                    result = left - right;
                };

                (indent + "Result: " + left.str() + " " + operator + " " + right.str() + " = " + result.str()).echo();
                result;
            };
        } else {
            /* Handle other node types */
            0;
        };
    };

    evaluate_with_trace(ast, 0);
};

/* Example usage */
"Interactive Calculator:".echo();
result = interactive_calculator("2 + 3 * 4");
("Final result: " + result.str()).echo();

Example: Prototype Web Framework

/* Simple web framework prototype */
simple_web_framework = op() {
    routes = {};

    {
        "get": op(path, handler) {
            routes.set("GET:" + path, handler);
        },
        "post": op(path, handler) {
            routes.set("POST:" + path, handler);
        },
        "handle_request": op(method, path, data) {
            route_key = method + ":" + path;
            if (routes.has(route_key)) {
                handler = routes.get(route_key);
                handler(data);
            } else {
                {"status": 404, "body": "Not Found"};
            };
        }
    };
};

/* Example usage */
app = simple_web_framework();

/* Define routes */
app.get("/hello", op(data) {
    {"status": 200, "body": "Hello, World!"};
});

app.post("/echo", op(data) {
    {"status": 200, "body": "Echo: " + data.get("message")};
});

/* Handle requests */
response1 = app.handle_request("GET", "/hello", {});
response2 = app.handle_request("POST", "/echo", {"message": "Hello from Grapa!"});

("Response 1: " + response1.get("body")).echo();
("Response 2: " + response2.get("body")).echo();