MALDA™ Reference Manual

The AI-First Programming Language - Version 1.0.39

Learn MALDA

A short course through the core language. Each lesson is one idea, one runnable file, and one chapter section. The numbered chapters stay the reference; this page is the spine.

The same order is Desktop Start With MALDA, the Web IDE student track, and Start Here.

How to run a file

How to get MALDA

You need the malda command, or an IDE that already has it:

The interpreter is the default. After malda is on your path, from the repo root:

malda Examples/Basics/hello_world.malda

That prints Hello, World! and exits. You do not need compile, an API key, or a project scaffold for this path. Diagnose without running with malda check. Editors: Desktop IDE is the Windows reference; Web IDE is a browser playground (not Desktop parity); VS Code + LSP is the cross-platform editor. The full command index is 2. Tools & Tooling.

Prefer namespaced calls (io.print, math.sqrt, str.upper). Flat print still runs.

Lesson 0 — First Look (optional)

If you already program, start here. -> Review binds the prompt to the schema. Without await, the call is a rendered template (no API key). validate("Review", …) is the same check await would run on the model JSON. Schema syntax: 4.6. Same file: Examples/Basics/first_look.malda.

schema Review {
    summary: string;
    issues: string[];
}

prompt codeReview(code, language) -> Review {
    system: "You are an expert reviewer of {language}.",
    user: "Review this {language} code:\n\n{code}"
}

var rendered = codeReview("function add(a, b) { return a + b; }", "javascript");
io.print(rendered.user);

var checked = validate("Review", {
    "summary": "Looks fine",
    "issues": []
});
if (checked.ok) {
    io.print("schema ok: " + checked.data.summary);
} else {
    io.print("schema failed: " + checked.error);
}
Try this: Change the validated summary to "Needs work" and re-run. What is the last printed line?
Answer

schema ok: Needs work

Write this: Declare schema Item { name: string; }. Validate { "name": "pen" }. If it succeeds, print schema ok: plus the name. Last line: schema ok: pen.
Answer
schema Item {
    name: string;
}

var checked = validate("Item", {
    "name": "pen"
});
if (checked.ok) {
    io.print("schema ok: " + checked.data.name);
} else {
    io.print("schema failed: " + checked.error);
}

Lesson 1 — Hello World

One call writes one line. Chapter: 12.1 Console output. Same file: Examples/Basics/hello_world.malda.

io.print("Hello, World!");
Try this: Change the string to "Hello, MALDA!" and re-run.
Answer

The program prints Hello, MALDA! and exits.

Write this: Print Good morning. on the first line and Ready. on the second. Last line: Ready.
Answer
io.print("Good morning.");
io.print("Ready.");

Lesson 2 — Variables and arithmetic

var declares a binding. The type comes from the value. $"Sum: {sum}" inserts the expression into the string; "Sum: " + string(sum) is the same. Chapter: 5.1 Variable declaration. Same file: Examples/Basics/variables_arithmetic.malda.

var x = 10;
var y = 20;
var sum = x + y;
var product = x * y;
io.print($"Sum: {sum}");
io.print($"Product: {product}");
Try this: Change 10 to 7 and re-run. What is the new sum?
Answer

27 (7 + 20).

Write this: Set var width = 4 and var height = 5. Print the product as Area: 20. Last line: Area: 20.
Answer
var width = 4;
var height = 5;
io.print("Area: " + string(width * height));

Lesson 3 — Conditionals

if / else if / else choose a branch. Chapter: 8.1 Conditional statements. Same file: Examples/Basics/conditionals.malda.

var age = 18;
if (age >= 18) {
    io.print("You are an adult");
} else {
    io.print("You are a minor");
}

var score = 85;
if (score >= 90) {
    io.print("Grade: A");
} else if (score >= 80) {
    io.print("Grade: B");
} else if (score >= 70) {
    io.print("Grade: C");
} else {
    io.print("Grade: F");
}
Try this: Change age to 16. What prints first?
Answer

You are a minor

Write this: Set var temp = 3. If temp < 0 print ice, else if temp < 10 print cold, else print warm. Last line: cold.
Answer
var temp = 3;
if (temp < 0) {
    io.print("ice");
} else if (temp < 10) {
    io.print("cold");
} else {
    io.print("warm");
}

Lesson 4 — While loop

A while loop repeats while the condition is true. Update the loop variable yourself. Chapter: 8.2 While. Same file: Examples/Basics/while_loop.malda.

var i = 1;
while (i <= 10) {
    io.print($"Count: {i}");
    i = i + 1;
}
io.print("Done!");
Try this: Change the loop to stop at 5. How many Count: lines print?
Answer

Five lines: Count: 1 through Count: 5.

Write this: Use while to print 2, then 4, then 6, then done. Last line: done.
Answer
var n = 2;
while (n <= 6) {
    io.print(n);
    n = n + 2;
}
io.print("done");

Lesson 5 — For loop

A C-style for packs init, condition, and increment. Chapter: 8.2 For. Same file: Examples/Basics/for_loop.malda.

for (var i = 1; i <= 10; i = i + 1) {
    io.print($"Number: {i}");
}
io.print("Loop finished!");
Try this: Change the loop to start at 5. What is the first Number: line?
Answer

Number: 5

Write this: Use a counted for to print 10, then 9, then 8. Last line: 8.
Answer
for (var i = 10; i >= 8; i = i - 1) {
    io.print(i);
}

Lesson 6 — Functions

The only function keyword is function. fn and def are syntax errors. Chapter: 9.1 Function declaration. Same file: Examples/Basics/functions.malda.

function add(a, b) {
    return a + b;
}

var result1 = add(5, 3);
io.print($"5 + 3 = {result1}");

var result2 = add(10, 2);
io.print($"10 + 2 = {result2}");
Try this: Add io.print(add(1, 1)); after the existing prints. What is the last line?
Answer

2

Write this: Write function greet(name) that returns "Hi, " + name. Print greet("Ada"). Last line: Hi, Ada.
Answer
function greet(name) {
    return "Hi, " + name;
}

io.print(greet("Ada"));

Lesson 7 — Lists and indexing

Arrays are zero-indexed and grow with append. A counted for walks indexes; for-in walks values. Chapter: 6. Arrays. Same file: Examples/Basics/lists_indexing.malda.

var scores = [88, 92, 75];
io.print("first=" + string(scores[0]));
io.print("length=" + string(scores.length));

scores.append(80);
io.print("after append length=" + string(scores.length));

var last = scores.pop();
io.print("popped=" + string(last));
io.print("length after pop=" + string(scores.length));

var total = 0;
for (var i = 0; i < scores.length; i = i + 1) {
    io.print("scores[" + string(i) + "]=" + string(scores[i]));
    total = total + scores[i];
}

var walked = 0;
for (var score in scores) {
    walked = walked + 1;
}

io.print("sum=" + string(total));
io.print("for-in count=" + string(walked));
io.print("lists ok");
Try this: After the existing append, append another score 100 and do not pop it. What is the new printed sum?
Answer

355 (88 + 92 + 75 + 100). The original file pops the appended 80 before summing.

Write this: Start with var nums = [1, 2, 3]. Append 4. Print last= plus the last value. Last line: last=4.
Answer
var nums = [1, 2, 3];
nums.append(4);
io.print("last=" + string(nums[nums.length - 1]));

Lesson 8 — Complete starter

Variables, a for-in loop, a function, and an if in one linear program — now that lists are familiar. Catalog note: 35.1. Same file: Examples/Basics/complete_starter_program.malda.

var cart = [12, 18, 7];
var total = 0;

for (var item in cart) {
    total = total + item;
}

function describeTotal(amount) {
    if (amount >= 30) {
        return "big order";
    }

    return "small order";
}

io.print($"Items: {cart.length}");
io.print($"Total: {total}");
io.print($"Summary: {describeTotal(total)}");
Try this: Change the last cart item from 7 to 4. Is it still a big order?
Answer

Yes. The total becomes 34, which is still >= 30.

Try this: Keep the original cart and change the threshold from 30 to 40. What is the summary?
Answer

small order (37 is below 40).

Write this: Sum var prices = [5, 5, 5] with for-in and print Total: 15. Last line: Total: 15.
Answer
var prices = [5, 5, 5];
var total = 0;
for (var price in prices) {
    total = total + price;
}
io.print("Total: " + string(total));

Lesson 9 — Input

io.input reads one line from stdin and always returns a string. Convert it if you need a number. This snippet waits for a keyboard, so it is not marked runnable here. Chapter: 12.2 Console input. Same file: Examples/Basics/input_example.malda.

var name = io.input("Enter your name: ");
var ageStr = io.input("Enter your age: ");
var age = int(ageStr);
io.print($"Hello, {name}. You are {age} years old.");

At end of input every later io.input returns "", not null. Prefer toIntOr(raw, fallback) over bare int(...) when the line may be blank.

Try this: What does every later io.input return at end of file?
Answer

An empty string "", not null.

Write this: Read one line with io.input("City: ") into city and print You live in plus that string. This waits for a keyboard, so it is not marked runnable here. At end of file city is "".
Answer
var city = io.input("City: ");
io.print("You live in " + city);

Lesson 10 — Dictionaries

A dict maps string keys to values. Index to read or write; containsKey, keys, and values inspect the map. Chapter: 4.4 Dictionaries. Same file: Examples/Basics/dictionary_example.malda.

var d = dict { "a": 1, "b": 2 };
io.print("a = " + d["a"]);
io.print("b = " + d["b"]);

d["c"] = 3;
io.print("c = " + d["c"]);

io.print("has b: " + d.containsKey("b"));
io.print("has missing: " + d.containsKey("missing"));

var keys = d.keys();
var values = d.values();

io.print("keys length: " + keys.length);
io.print("values length: " + values.length);
Try this: Add d["d"] = 4; and print it. What is keys.length after that?
Answer

4

Write this: Make a dict with key "ok" set to true. Print ok= plus the value. Last line: ok=true.
Answer
var flags = dict { "ok": true };
io.print("ok=" + flags["ok"]);

Lesson 11 — Recursion

A function may call itself. Write a base case that stops, then a smaller argument. Chapter: 9.4 Recursion. Same file: Examples/Basics/recursion.malda.

function factorial(n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

function countdown(n) {
    if (n <= 0) {
        io.print("liftoff");
        return 0;
    }
    io.print(n);
    return countdown(n - 1);
}

io.print("factorial(5)=" + string(factorial(5)));
io.print("countdown from 3:");
countdown(3);
io.print("recursion ok");
Try this: Print factorial(7). What is the value?
Answer

5040

Write this: Write function sumTo(n) that returns 1 when n <= 1, else n + sumTo(n - 1). Print sumTo(4). Last line: 10.
Answer
function sumTo(n) {
    if (n <= 1) {
        return 1;
    }
    return n + sumTo(n - 1);
}

io.print(sumTo(4));

Lesson 12 — Classes

A class is a named type with fields and methods. new ClassName(...) runs the constructor. Inside a method you can read a field as name; write this.name when a parameter shadows the field (as the constructor does). Chapter: 11.1 A working class. Same file: Examples/Basics/classes_intro.malda.

class Person {
    public var name;
    public var age;

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    public function introduce() {
        io.print("Hi, I'm " + name + " and I'm " + string(age) + " years old.");
    }
}

var alice = new Person("Alice", 30);
alice.introduce();
io.print("age=" + string(alice.age));
Try this: Construct a second person new Person("Bob", 25) and call introduce(). What is the new last introduce line?
Answer

Hi, I'm Bob and I'm 25 years old.

Write this: Write class Box with public var w, constructor Box(w), and public function area() that returns w * w. Print new Box(3).area(). Last line: 9.
Answer
class Box {
    public var w;

    function Box(w) {
        this.w = w;
    }

    public function area() {
        return w * w;
    }
}

io.print(new Box(3).area());

Lesson 13 — try / catch

try runs code that may fail. catch handles the thrown value. finally always runs. Chapter: 8.4 Exception handling. Same file: Examples/Basics/try_catch.malda.

try {
    throw "something went wrong";
} catch (error) {
    io.print("caught: " + error);
}

try {
    io.print("in try");
} catch (error) {
    io.print("caught: " + error);
} finally {
    io.print("cleanup");
}
Try this: Change the thrown string to "disk full". What is the first printed line?
Answer

caught: disk full

Fix this: Move throw "something went wrong"; to before the try block. What happens?
Answer

The program stops with an uncaught error. catch only handles throws that run inside its try.

Write this: In a try, throw "nope". In catch, print err= plus the thrown value. Last line: err=nope.
Answer
try {
    throw "nope";
} catch (error) {
    io.print("err=" + error);
}

Lesson 14 — Prompt as a template

A prompt is a callable template. Without await it does not call a model. Chapter: 10.1 Overview step 1. Same file: Examples/Basics/prompt_template.malda.

prompt greet(name) {
    user: "Hello, {name}! How are you today?"
}

var greeting = greet("Alice");
io.print(greeting.user);
Try this: Call greet("MALDA") instead. What prints?
Answer

Hello, MALDA! How are you today?

Write this: Write prompt bye(name) with user: "Goodbye, {name}.". Print bye("Ada").user. Last line: Goodbye, Ada.
Answer
prompt bye(name) {
    user: "Goodbye, {name}."
}

io.print(bye("Ada").user);

Lesson 15 — Mini project

A class, a try, and offline schema + validate in one linear program. Catalog note: 35.1. Same file: Examples/Basics/gradebook.malda.

schema Score {
    name: string;
    points: int;
}

class Grade {
    public var name;
    public var points;

    function Grade(name, points) {
        this.name = name;
        this.points = points;
    }

    public function label() {
        if (points >= 90) {
            return "A";
        }

        return "B";
    }
}

var ada = new Grade("Ada", 92);
io.print(ada.name + ": " + ada.label());

try {
    int("not-a-number");
} catch (error) {
    io.print("caught bad score");
}

var checked = validate("Score", {
    "name": "Ada",
    "points": 92
});
if (checked.ok) {
    io.print("schema ok: " + checked.data.name);
} else {
    io.print("schema failed: " + checked.error);
}
Try this: Change Ada's points from 92 to 88. What is the first printed line?
Answer

Ada: B

Write this: Declare schema Item { label: string; }. Validate { "label": "pen" }. If it succeeds, print schema ok: plus the label. Last line: schema ok: pen.
Answer
schema Item {
    label: string;
}

var checked = validate("Item", {
    "label": "pen"
});
if (checked.ok) {
    io.print("schema ok: " + checked.data.label);
} else {
    io.print("schema failed: " + checked.error);
}

Lesson 16 — Check a mistake

malda check diagnoses a file and does not run it. fn and def are not function keywords — check names them. Chapter: 2.1.2 Diagnose without executing. Same file (the fixed program): Examples/Basics/check_a_mistake.malda.

Paste this broken twin into a scratch file and run malda check scratch.malda. It is not marked runnable here.

fn add(a, b) {
    return a + b;
}

var nums = [1, 2, 3];
io.print(nums.length());

Check reports 'fn' is not a function keyword. Use 'function'. Then open the fixed file and run it:

function add(a, b) {
    return a + b;
}

var nums = [1, 2, 3];
io.print("sum=" + string(add(2, 3)));
io.print("len=" + string(nums.length));
Try this: After you change fn to function, what does malda check still flag on nums.length()?
Answer

.length() should be .length (a property, not a call). malda check --fix can rewrite that one.

Write this: Write function double(n) that returns n * 2. Print double(4) and the length of [1, 2] as len=2. Last line: len=2.
Answer
function double(n) {
    return n * 2;
}

io.print(double(4));
io.print("len=" + string([1, 2].length));

Lesson 17 — Two files and a test

include "path"; splices another .malda file at the top level (relative to this file). That is not import / export. Chapter: 1.6 Source composition. Same file: Examples/Basics/modules_include.malda (helper: Examples/Basics/helpers/greet_lib.malda).

include "helpers/greet_lib.malda";

io.print(greet("MALDA"));
io.print("2 + 3 = " + add(2, 3));
io.print("Done.");

Ordinary malda run is the wrong command for tests. Run:

malda test Examples/Testing/unit_test_basics.test.malda

That file uses assert. First section of the test chapter: 36. Property Testing.

function add(a, b) {
    return a + b;
}

function factorial(n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

function bound(value, lo, hi) {
    if (value < lo) {
        return lo;
    }
    if (value > hi) {
        return hi;
    }
    return value;
}

assert(add(2, 3) == 5, "add(2, 3) should be 5");
assert(factorial(5) == 120, "factorial(5) should be 120");
assert(bound(15, 0, 10) == 10, "bound should cap at hi");
assert(bound(-3, 0, 10) == 0, "bound should floor at lo");
assert(bound(7, 0, 10) == 7, "bound should pass through in-range values");

io.print("unit_test_basics: all asserts passed");
Write this: Keep function add(a, b). Add assert(add(10, 5) == 15, "add(10, 5) should be 15"); and print extra assert ok. Last line: extra assert ok.
Answer
function add(a, b) {
    return a + b;
}

assert(add(10, 5) == 15, "add(10, 5) should be 15");
io.print("extra assert ok");

Lesson 18 — Offline prompt eval

evalPrompt runs the same validate path as await, with a fixture instead of a model. No API key. Chapter: 10. Prompts after the first-read stop (fixture / evalPrompt, not Mode B/C). Same file: Examples/Basics/prompt_eval.malda. Optional extra: Examples/Prompts/eval_prompt.malda.

schema Card {
    name: string;
    email: string;
}

prompt extractCard(raw) -> Card {
    system: "Extract a contact. JSON only.";
    user: raw;
}

var instance = extractCard("Ada Lovelace — ada@example.com");

var ok = evalPrompt(instance, dict { "name": "Ada", "email": "ada@example.com" });
if (ok.ok) {
    io.print("card: " + ok.data.name);
} else {
    io.print("card fail");
}

var bad = evalPrompt(instance, dict { "email": "nope" });
if (!bad.ok) {
    io.print("card expected failure");
}
Write this: Declare schema Note { text: string; } and prompt makeNote(raw) -> Note with user: raw. Call evalPrompt(makeNote("x"), dict { "text": "hi" }). If it succeeds, print note: hi. Last line: note: hi.
Answer
schema Note {
    text: string;
}

prompt makeNote(raw) -> Note {
    user: raw;
}

var checked = evalPrompt(makeNote("x"), dict { "text": "hi" });
if (checked.ok) {
    io.print("note: " + checked.data.text);
} else {
    io.print("note fail");
}

After the core path

The core course ends at offline prompt eval. Next, pick one track — one file, one first-read box — instead of scanning the sidebar:

  1. Algorithms — Examples/Algorithms/towers_of_hanoi.malda. Recursion you already know, applied to a puzzle. Then the rest of the short Algorithms list on Start Here.
  2. Then one hub — stop at the first-read box, then come back:
    • Prompts: 10.1 step 1 (template, no API key)
    • Stdlib: 13.0 namespaced calls
    • Agents: 19.0 (skip the security essay on first read)
    • Workflows: 23.0
    • Web: 25 — pick one row in the table

See Also