diff options
Diffstat (limited to 'js/baba-yaga/docs/00_crash-course.md')
-rw-r--r-- | js/baba-yaga/docs/00_crash-course.md | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/js/baba-yaga/docs/00_crash-course.md b/js/baba-yaga/docs/00_crash-course.md new file mode 100644 index 0000000..0327e5e --- /dev/null +++ b/js/baba-yaga/docs/00_crash-course.md @@ -0,0 +1,986 @@ +# Baba Yaga Crash Course + +## Language Overview +Baba Yaga is a functional scripting language emphasizing immutability, pattern matching, and explicit error handling. It features currying, anonymous functions, recursive functions, and a useful `when` expression for control flow. + +## Core Syntax Rules + +### Comments and Statements +```baba +// Single line comments start with // + +variable : 42; // Variable declaration +function : x -> x + 1; // Function declaration +``` + +### Data Types and Literals + +**Numbers:** +```baba +integerValue : 42; // Int type +floatValue : 3.14; // Float type +negativeValue : -10; // Negative numbers +``` + +**Strings:** +```baba +greeting : "Hello World"; // String type +concatenated : "Hello" .. " " .. "World"; // String concatenation with .. or str.concat +``` + +**Booleans:** +```baba +isTrue : true; +isFalse : false; +``` + +**Mathematical Constants:** +```baba +pi : PI; // Built-in π constant +infinity : INFINITY; // Built-in infinity +``` + +**Lists (Immutable):** +```baba +numbers : [1, 2, 3, 4]; +mixed : [1, "hello", true]; +firstElement : numbers.0; // Zero-based indexing +secondElement : numbers.1; +``` + +**Tables (Immutable Key-Value):** +```baba +person : {name: "Lucy Snowe", age: 23, active: true}; +userName : person.name; // Property access +userAge : person.age; +``` + +### Type System and Declarations + +**Optional Type Annotations:** +```baba +// Optional type declaration +myNumber Int; +myNumber : 42; + +// Direct assignment with type inference +greeting : "Hello"; // Type inferred as String +``` + +**Type Hierarchy:** +- `Int` ⊂ `Float` ⊂ `Number` (`Int` can be used where `Float` expected) +- `String`, `Bool`, `List`, `Table`, `Result` are distinct types + +## Functions + +### Basic Functions +```baba +// Simple function +add : x y -> x + y; +result : add 5 3; // Function call: 8 + +// Single parameter function +square : x -> x * x; +squared : square 4; // 16 +``` + +### Anonymous Functions +```baba +// Anonymous function +doubler : x -> x * 2; + +// Immediately invoked +result : (x -> x + 1) 5; // 6 + +// In table literals +calculator : { + add: x y -> x + y; + multiply: x y -> x * y; +}; +sum : calculator.add 10 20; // 30 +``` + +### Currying and Partial Application +```baba +// Curried function (multiple arrows) +add : x -> y -> x + y; +add5 : add 5; // Partial application +result : add5 3; // 8 + +// Multi-level currying +addThree : x -> y -> z -> x + y + z; +addTwoMore : addThree 1; // Partially applied +addOne : addTwoMore 2; // Partially applied +final : addOne 3; // 6 +``` + +### Typed Functions +```baba +// Function with parameter and return types +add : (x: Int, y: Int) -> Int -> x + y; +multiply : (x: Float, y: Float) -> Float -> x * y; + +// Curried typed function +curriedAdd : (x: Int) -> (Int -> Int) -> y -> x + y; +``` + +### Recursive Functions +```baba +// Simple recursion +factorial : n -> + when n is + 0 then 1 + 1 then 1 + _ then n * (factorial (n - 1)); + +// Fibonacci +fibonacci : n -> + when n is + 0 then 0 + 1 then 1 + _ then (fibonacci (n - 1)) + (fibonacci (n - 2)); +``` + +### Local Bindings (`with`/`with rec`) + +```baba +// Non-recursive local bindings +addMul : x y -> with (inc : x + 1; prod : inc * y;) -> inc + prod; + +// Typed locals +sumNext : (x: Int, y: Int) -> Int -> + with (nx Int; ny Int; nx : x + 1; ny : y + 1;) -> nx + ny; + +// Mutually recursive locals +evenOdd : z -> with rec ( + isEven : n -> when n is 0 then true _ then isOdd (n - 1); + isOdd : n -> when n is 0 then false _ then isEven (n - 1); +) -> {even: isEven z, odd: isOdd z}; +``` + +**Common Patterns and Use Cases:** + +```baba +// 1. Computed intermediate values (avoiding repetition) +quadraticRoots : a b c -> + with ( + discriminant : b * b - 4 * a * c; + sqrtDisc : math.sqrt discriminant; + denominator : 2 * a; + ) -> + { + r1: (-b + sqrtDisc) / denominator, + r2: (-b - sqrtDisc) / denominator + }; + +// 2. Complex calculations with named steps +calculateTax : income deductions -> + with ( + taxableIncome : income - deductions; + taxRate : when (taxableIncome <= 50000) is + true then 0.15 + _ then when (taxableIncome <= 100000) is + true then 0.25 + _ then 0.35; + baseTax : taxableIncome * taxRate; + finalTax : when (baseTax < 1000) is true then 1000 _ then baseTax; + ) -> + finalTax; + +// 3. Data transformation pipelines +processUserData : user -> + with ( + normalizedName : str.upper (str.trim user.name); + ageGroup : when (user.age < 18) is + true then "minor" + _ then when (user.age < 65) is + true then "adult" + _ then "senior"; + status : when user.active is + true then "active" + false then "inactive"; + ) -> + { + id: user.id, + displayName: normalizedName, + category: ageGroup, + status: status + }; + +// 4. Error handling with multiple validations +validateOrder : order -> + with ( + hasItems : (length order.items) > 0; + hasValidTotal : order.total > 0; + // Note: Baba Yaga doesn't have null, so we'll use a different validation + hasValidShipping : (length order.shippingAddress) > 0; + allValid : hasItems and hasValidTotal and hasValidShipping; + ) -> + when allValid is + true then Ok order + false then Err "Order validation failed"; + +// 5. Complex pattern matching with computed values +classifyTriangle : a b c -> + with ( + sorted : [math.min a b, math.max a b, math.max (math.max a b) c]; + side1 : sorted.0; + side2 : sorted.1; + side3 : sorted.2; + isValid : ((side1 + side2) > side3); + isEquilateral : ((a = b) and (b = c)); + isIsosceles : ((a = b) or (b = c) or (a = c)); + isRight : (math.abs ((side1 * side1 + side2 * side2) - (side3 * side3))) < 0.001; + ) -> + when isValid is + false then "Invalid triangle" + true then when isEquilateral is + true then "Equilateral" + false then when isIsosceles is + true then when isRight is + true then "Right isosceles" + false then "Isosceles" + false then when isRight is + true then "Right scalene" + false then "Scalene"; + +// 6. Mutually recursive functions (with rec) +// Binary tree operations +treeOperations : tree -> + with rec ( + // Count total nodes + countNodes : t -> + when (isEmptyTable t) is + true then 0 + false then 1 + (countNodes t.left) + (countNodes t.right); + + // Calculate tree height + treeHeight : t -> + when (isEmptyTable t) is + true then 0 + false then 1 + (math.max (treeHeight t.left) (treeHeight t.right)); + + // Check if tree is balanced + isBalanced : t -> + when (isEmptyTable t) is + true then true + false then + (math.abs ((treeHeight t.left) - (treeHeight t.right)) <= 1) and + (isBalanced t.left) and + (isBalanced t.right); + ) -> + { + nodeCount: countNodes tree, + height: treeHeight tree, + balanced: isBalanced tree + }; + +// 7. State machine with recursive state transitions +trafficLight : initialState -> + with rec ( + // State transition function + nextState : current -> + when current is + "red" then "green" + "green" then "yellow" + "yellow" then "red"; + + // Count transitions until back to start + countCycles : start current count -> + when current = start is + true then count + false then countCycles start (nextState current) (count + 1); + + // Get state after N transitions + stateAfter : current n -> + when n is + 0 then current + _ then stateAfter (nextState current) (n - 1); + ) -> + { + cycles: countCycles initialState initialState 0, + after10: stateAfter initialState 10, + next: nextState initialState + }; + +// 8. Combinatorial functions with shared helpers +combinatorics : n r -> + with rec ( + // Factorial function + factorial : k -> + when k is + 0 then 1 + 1 then 1 + _ then k * (factorial (k - 1)); + + // Permutation: P(n,r) = n! / (n-r)! + permutation : n r -> + factorial n / (factorial (n - r)); + + // Combination: C(n,r) = n! / (r! * (n-r)!) + combination : n r -> + factorial n / ((factorial r) * (factorial (n - r))); + ) -> + { + n: n, + r: r, + permutations: permutation n r, + combinations: combination n r + }; +``` + +**Key Benefits of `with` and `with rec`:** + +1. **Avoid Repetition**: Compute values once and reuse them +2. **Improve Readability**: Give meaningful names to intermediate calculations +3. **Enable Complex Logic**: Break down complex operations into clear steps +4. **Mutual Recursion**: `with rec` allows local functions to call each other +5. **Scoped Variables**: Local bindings don't pollute global scope +6. **Type Safety**: Can declare types for local variables +7. **Performance**: Avoid recalculating expensive operations +8. **Maintainability**: Centralize related logic in one place + +**When to Use `with` vs `with rec`:** + +- **Use `with`** when you need local bindings for computed values, intermediate results, or simple helper functions that don't call each other +- **Use `with rec`** when you need mutually recursive functions or when local functions need to reference each other + +**Best Practices:** + +```baba +// Good: Clear, focused with blocks +processData : data -> + with ( + cleaned : str.trim data; + normalized : str.lower cleaned; + validated : (length normalized) > 0; + ) -> + when validated is + true then Ok normalized + false then Err "Empty data"; + +// Love it: Logical grouping of related operations +analyzeNumbers : numbers -> + with ( + count : length numbers; + sum : reduce (acc x -> acc + x) 0 numbers; + average : when count > 0 then sum / count _ else 0; + sorted : sort numbers; + median : when count % 2 = 0 then + (sorted.(count / 2 - 1) + sorted.(count / 2)) / 2 + _ else sorted.(count / 2); + ) -> + {count, sum, average, median}; + +// Oh no! Avoid: Overly complex with blocks +// Instead, break into smaller functions +processUser : user -> + with ( + // Too many bindings - consider breaking into helper functions + nameValid : (length user.name) > 0; + emailValid : (length user.email) > 0; // Simplified validation + ageValid : (user.age >= 0) and (user.age <= 150); + phoneValid : (length user.phone) >= 10; + addressValid : (length user.address) > 0; // Simplified validation + preferencesValid : (length user.preferences) > 0; + allValid : (nameValid and emailValid and ageValid and phoneValid and addressValid and preferencesValid); + ) -> + when allValid is + true then Ok user + _ then Err "Validation failed"; + +// Better: Break into focused functions +validateUserBasic : user -> + with ( + nameValid : (length user.name) > 0; + emailValid : (length user.email) > 0; // Simplified validation + ageValid : (user.age >= 0) and (user.age <= 150); + ) -> + (nameValid and emailValid and ageValid); + +validateUserContact : user -> + with ( + phoneValid : (length user.phone) >= 10; + // Note: Baba Yaga doesn't have null, so we'll use a different validation + addressValid : (length user.address) > 0; + ) -> + (phoneValid and addressValid); + +processUser : user -> + when ((validateUserBasic user) and (validateUserContact user)) is + true then Ok user + _ then Err "Validation failed"; +``` + +**Common Anti-patterns to Avoid:** + +```baba +// Don't: Use with for simple expressions +badExample : x -> + with (result : x + 1;) -> result; // Just use: x -> x + 1 + +// Don't: Nest with blocks unnecessarily +nestedBad : x -> + with (a : x + 1;) -> + with (b : a * 2;) -> + with (c : b + 3;) -> c; // Use: with (a: x+1; b: a*2; c: b+3;) -> c + +// Don't: Use with rec when simple recursion will do the trick +simpleRecursion : n -> + when n is + 0 then 1 + _ then n * (simpleRecursion (n - 1)); // No need for with rec + +// Do: Use with rec for mutual recursion +mutualRecursion : n -> + with rec ( + isEven : x -> when x is 0 then true _ then isOdd (x - 1); + isOdd : x -> when x is 0 then false _ then isEven (x - 1); + ) -> + isEven n; +``` + +## Pattern Matching with `when` + +### Basic Pattern Matching +```baba +// Literal patterns +checkNumber : num -> + when num is + 0 then "Zero" + 1 then "One" + 2 then "Two" + _ then "Other"; // Wildcard matches anything +``` + +### Multiple Discriminants +```baba +checkCoords : x y -> + when x y is + 0 0 then "Origin" + 1 1 then "Diagonal" + _ _ then "Somewhere else"; +``` + +### Type Patterns +```baba +checkType : value -> + when value is + Int then "It's an integer" + String then "It's a string" + Bool then "It's a boolean" + _ then "Unknown type"; +``` + +### Result Pattern Matching +```baba +processResult : result -> + when result is + Ok value then value * 2 // 'value' binds to inner data + Err message then 0; // 'message' binds to error string +``` + +## Error Handling with Result Type + +Baba Yaga uses the `Result` type for explicit error handling instead of exceptions. See [Error Handling](./06_error-handling.md) for comprehensive coverage. + +```baba +// Function returning Result +divide : x y -> + when y is + 0 then Err "Division by zero" + _ then Ok (x / y); + +// Using Result +result : divide 10 2; // Ok 5 +errorResult : divide 5 0; // Err "Division by zero" + +// Pattern matching on Result +handleDivision : x y -> + when (divide x y) is + Ok value then value + Err msg then 0; +``` + +## Operators and Precedence + +### Arithmetic Operators +```baba +addition : 5 + 3; // 8 +subtraction : 10 - 4; // 6 +multiplication : 6 * 7; // 42 +division : 15 / 3; // 5 +modulo : 17 % 5; // 2 +unaryMinus : -42; // -42 +``` + +### Comparison Operators +```baba +equal : 5 = 5; // true +notEqual : 5 != 3; // true +greater : 5 > 3; // true +less : 3 < 5; // true +greaterEqual : 5 >= 5; // true +lessEqual : 3 <= 5; // true +``` + +### Logical Operators +```baba +andResult : true and false; // false +orResult : true or false; // true +xorResult : true xor true; // false +``` + +### String Concatenation +```baba +combined : "Hello" .. " " .. "World"; // "Hello World" +``` + +### Operator Precedence (highest to lowest) +1. `*`, `/`, `%` (multiplication, division, modulo) +2. `+`, `-` (addition, subtraction) +3. `=`, `!=`, `>`, `<`, `>=`, `<=` (comparison) +4. `xor` +5. `and` +6. `or` +7. `..` (string concatenation) + +## Built-in Functions + +### Higher-Order List Functions +```baba +numbers : [1, 2, 3, 4, 5]; + +// map: apply function to each element +doubled : map (x -> x * 2) numbers; // [2, 4, 6, 8, 10] + +// filter: keep elements matching predicate +evens : filter (x -> x % 2 = 0) numbers; // [2, 4] + +// reduce: fold list to single value +sum : reduce (acc x -> acc + x) 0 numbers; // 15 +``` + +### Immutable List Operations +```baba +original : [1, 2, 3]; + +// append: add to end +withFour : append original 4; // [1, 2, 3, 4] + +// prepend: add to beginning +withZero : prepend 0 original; // [0, 1, 2, 3] + +// concat: combine lists +combined : concat [1, 2] [3, 4]; // [1, 2, 3, 4] + +// update: replace at index +updated : update original 1 99; // [1, 99, 3] + +// removeAt: remove at index +removed : removeAt original 0; // [2, 3] + +// slice: extract sublist +sublist : slice original 0 2; // [1, 2] + +// Note: original list is never modified! +``` + +### Immutable Table Operations +```baba +user : {name: "Alice", age: 30}; + +// set: add/update property +updated : set user "city" "Boston"; // {name: "Alice", age: 30, city: "Boston"} + +// remove: delete property +minimal : remove user "age"; // {name: "Alice"} + +// merge: combine tables (second overrides first) +merged : merge user {country: "USA"}; // {name: "Alice", age: 30, country: "USA"} + +// keys: get all keys as list +keyList : keys user; // ["name", "age"] + +// values: get all values as list +valueList : values user; // ["Alice", 30] +``` + +### String Operations +```baba +// String concatenation +combined : str.concat "Hello" " " "World"; // "Hello World" + +// Split string into list +words : str.split "a,b,c" ","; // ["a", "b", "c"] + +// Join list into string +sentence : str.join ["Hello", "World"] " "; // "Hello World" + +// String length +len : str.length "Hello"; // {value: 5, isFloat: false} + +// Substring +part : str.substring "Hello World" 0 5; // "Hello" + +// Replace +replaced : str.replace "Hello World" "World" "Universe"; // "Hello Universe" + +// Trim whitespace +clean : str.trim " Hello "; // "Hello" + +// Case conversion +upper : str.upper "hello"; // "HELLO" +lower : str.lower "WORLD"; // "world" +``` + +### Math Operations +```baba +// Basic math functions +absolute : math.abs -5; // {value: 5, isFloat: true} +minimum : math.min 3 7; // {value: 3, isFloat: true} +maximum : math.max 3 7; // {value: 7, isFloat: true} +clamped : math.clamp 10 0 5; // {value: 5, isFloat: true} + +// Rounding +floored : math.floor 3.7; // {value: 3, isFloat: true} +ceiled : math.ceil 3.2; // {value: 4, isFloat: true} +rounded : math.round 3.5; // {value: 4, isFloat: true} + +// Powers and roots +powered : math.pow 2 3; // {value: 8, isFloat: true} +squareRoot : math.sqrt 16; // {value: 4, isFloat: true} + +// Trigonometry (radians) +sine : math.sin 0; // {value: 0, isFloat: true} +cosine : math.cos 0; // {value: 1, isFloat: true} + +// Random numbers +random : math.random; // Random float 0 <= x < 1 +randomInt : math.randomInt 1 6; // Random integer 1-6 inclusive +``` + +### Enhanced Random Operations +```baba +// Enhanced random utilities +numbers : [1, 2, 3, 4, 5]; +choice : random.choice numbers; // Random element from list +shuffled : random.shuffle numbers; // Shuffled copy of list +randomNum : random.range 1 10; // Random integer 1-10 +random.seed 42; // Set random seed (placeholder) +``` + +### Data Validation +```baba +// Input validation utilities +isValid : validate.notEmpty "hello"; // true +isEmpty : validate.notEmpty ""; // false +inRange : validate.range 1 10 5; // true +validEmail : validate.email "user@domain.com"; // true +correctType : validate.type "Int" 42; // true +``` + +### Text Processing +```baba +// Enhanced text utilities +multiline : "line1\nline2\nline3"; // Note: \n is literal, not newline +lines : text.lines multiline; // ["line1\\nline2\\nline3"] (single item) +words : text.words "hello world test"; // ["hello", "world", "test"] +padded : text.padLeft 10 "hi"; // " hi" +aligned : text.padRight 10 "hi"; // "hi " +``` + +### Data Transformation +```baba +// Sorting with custom criteria +people : [ + {name: "Alice", age: 30}, + {name: "Bob", age: 25}, + {name: "Charlie", age: 35} +]; +byAge : sort.by people (p -> p.age); // Sorted by age: Bob, Alice, Charlie + +// Grouping data +numbers : [1, 2, 3, 4, 5, 6]; +grouped : group.by numbers (x -> x % 2 = 0); // Groups by even/odd +evenNums : grouped."true"; // [2, 4, 6] +oddNums : grouped."false"; // [1, 3, 5] +``` + +### Utility Functions +```baba +// Array chunking (APL-style windowing) +data : [1, 2, 3, 4, 5, 6]; +chunks : chunk data 2; // [[1, 2], [3, 4], [5, 6]] + +// Range generation +sequence : range 1 5; // [1, 2, 3, 4, 5] +countdown : range 5 1; // [5, 4, 3, 2, 1] + +// Value repetition +repeated : repeat 3 "hello"; // ["hello", "hello", "hello"] +``` + +### Debug and Development Tools +```baba +// Enhanced debugging with type information +debug.print 42; // [DEBUG] 42 (Int) +debug.print (x -> x * 2); // [DEBUG] <function: (x) -> ...> (Unknown) + +// Detailed value inspection +myFunc : x -> x + 1; +details : debug.inspect myFunc; // Returns detailed type information + +// Assertions with custom messages +assert (2 + 2 = 4) "Math should work"; // Passes silently +// assert (2 + 2 = 5) "This fails"; // Throws: "Assertion failed: This fails" +``` + +### I/O Operations + +**Basic Output:** +```baba +// Output to console +io.out "Hello World"; +io.out 42; +io.out [1, 2, 3]; + +// Read input (returns string) +input : io.in; +``` + +**Enhanced Output with `io.print`:** + +The `io.print` function provides formatting for different data types, making output more easily readable: + +```baba +// Automatic grid detection for 2D arrays +gameBoard : [ + [1, 0, 1], + [0, 1, 0], + [1, 0, 1] +]; + +io.print gameBoard; +// Output: +// █·█ +// ·█· +// █·█ + +// Labeled output with format strings +io.print "Game Board" gameBoard; +io.print "Score" 1500; +io.print "Player" "Alice"; + +// Perfect for Conway's Game of Life, chess boards, mazes, etc. +glider : [ + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [1, 1, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0] +]; + +io.print "Glider Pattern Evolution:"; +io.print "Step 0:"; +io.print glider; +// Output: +// Glider Pattern Evolution: +// Step 0: +// ·█··· +// ··█·· +// ███·· +// ····· +// ····· + +// Enhanced display of other data types +myFunction : x -> x * 2; +result : Ok 42; +error : Err "Something went wrong"; + +io.print "Function" myFunction; // Function: <function> +io.print "Success" result; // Success: Ok(42) +io.print "Failure" error; // Failure: Err(Something went wrong) +``` + +**Key `io.print` Features:** +- **Automatic Grid Detection**: 2D numeric arrays display as visual grids with `█` (alive/1) and `·` (dead/0) +- **Clean Function Display**: Shows `<function>` instead of complex internal representations +- **Enhanced Result Types**: Displays `Ok(value)` and `Err(message)` in readable format +- **Labeled Output**: Use format strings like `io.print "Label" data` for organized output +- **Educational Value**: Perfect for teaching algorithms, game development, data visualization +- **Backward Compatible**: Works as a drop-in replacement for `io.out` in most cases + +### Introspection +```baba +// Get shape information about values +listInfo : shape [1, 2, 3]; +// Returns: {kind: "List", rank: 1, shape: [3], size: 3, isEmpty: false} + +stringInfo : shape "hello"; +// Returns: {kind: "String", rank: 1, shape: [5], size: 5, isEmpty: false} + +tableInfo : shape {a: 1, b: 2}; +// Returns: {kind: "Table", rank: 1, shape: [2], size: 2, keys: ["a", "b"], isEmpty: false} +``` + +## Complete Examples + +### Calculator with Pattern Matching +```baba +calculate : op x y -> + when op is + "add" then (x + y) + "subtract" then (x - y) + "multiply" then (x * y) + "divide" then + when y is + 0 then Err "Division by zero" + _ then Ok (x / y) + _ then Err "Unknown operation"; + +result1 : calculate "add" 5 3; // 8 +result2 : calculate "divide" 10 0; // Err "Division by zero" +``` + +### List Processing Pipeline +```baba +numbers : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +// Find sum of squares of even numbers +evenSquareSum : reduce (acc x -> acc + x) 0 + (map (x -> x * x) + (filter (x -> x % 2 = 0) numbers)); +// Result: 220 (4 + 16 + 36 + 64 + 100) +``` + +### Tree Processing with Recursion +```baba +isEmptyTable : t -> (length (keys t)) = 0; + +treeHeight : tree -> + when (isEmptyTable tree) is + true then 0 + false then + when (isEmptyTable tree.left) (isEmptyTable tree.right) is + true true then 1 + _ _ then 1 + (math.max (treeHeight tree.left) + (treeHeight tree.right)); + +myTree : { +value: 1, + left: {value: 2, left: {}, right: {}}, + right: {value: 3, left: {}, right: {}} +}; + +height : treeHeight myTree; // 2 +``` + +### Error Handling Chain +```baba +// Chain of operations that might fail +processData : input -> + when (parseNumber input) is + Err msg then Err msg + Ok num then + when (num / 2) > 10 is + true then Ok (num / 2) + false then Err "Result too small"; + +parseNumber : str -> + when str is + "0" then Ok 0 + "10" then Ok 10 + "20" then Ok 20 + _ then Err "Invalid number"; + +result : processData "20"; // Returns Err "Result too small" (10 is not > 10) +``` + +## Key Patterns + +1. **Immutability**: All data structures are immutable. Use built-in functions like `append`, `set`, etc. +2. **Pattern Matching**: Use `when` expressions for control flow instead of if/else chains. +3. **Error Handling**: Use `Result` type with `Ok`/`Err` variants instead of exceptions. +4. **Function Composition**: Build complex behavior by composing simple functions. +5. **Recursion**: Use recursive functions with pattern matching for iteration-like behavior. +6. **Type Safety**: Use optional type annotations for better error detection. + +## Function Call Syntax + +- Parentheses are optional: `add 5 3` or `(add 5 3)` +- Function calls are left-associative: `f x y z` means `((f x) y) z` +- Use parentheses to group: `f (g x) y` applies `g` to `x` first + +## Misc. Important Notes + +- **Whitespace**: Significant for function calls (spaces separate arguments) +- **Mutability**: Everything is immutable - operations return new values +- **Type Coercion**: `Int` automatically promotes to Float when needed +- **Error Strategy**: Use `Result` type, not exceptions +- **Recursion**: Preferred over loops for iteration +- **Variables**: Actually immutable bindings, not mutable variables + +## Execution Model and Environment + +- **Entry point**: Programs execute top-to-bottom at the file’s top level. There is no required `main` function; define and call one yourself if needed or if you like them. +- **Modules**: No built-in import/export system. Larger programs are typically single-file or orchestrated by a host embedding (see `../IO.md`, WIP). +- **Standard library scope**: + - In addition to items earlier, available built-ins include: + - **General**: `length` (works on lists and strings), `chunk`, `range`, `repeat`, `assert` + - **Array Programming**: `scan`, `cumsum`, `cumprod`, `at`, `where`, `take`, `drop`, `broadcast`, `zipWith`, `reshape`, `flatMap` + - **Function Combinators**: `flip`, `apply`, `pipe`, `compose` + - **String namespace `str`**: `concat`, `split`, `join`, `length`, `substring`, `replace`, `trim`, `upper`, `lower` + - **Text namespace `text`**: `lines`, `words`, `padLeft`, `padRight` + - **Math namespace `math`**: `abs`, `sign`, `floor`, `ceil`, `round`, `trunc`, `min`, `max`, `clamp`, `pow`, `sqrt`, `exp`, `log`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `deg`, `rad`, `random`, `randomInt` + - **Random namespace `random`**: `choice`, `shuffle`, `range`, `seed` + - **Validation namespace `validate`**: `notEmpty`, `range`, `email`, `type` + - **Sorting namespace `sort`**: `by` + - **Grouping namespace `group`**: `by` + - **Debug namespace `debug`**: `print`, `inspect` + - **IO namespace `io`**: `out`, `in`, `print`, and (host-enabled) event functions `io.emit`, `io.listen` + +## Syntax Clarifications + +- **Statement termination**: Top-level statements, table fields, and parentheses bodies accept a trailing `;` if present. +- **Whitespace**: Only significant for function calls (spaces separate arguments). Indentation/newlines do not affect `when` or other constructs. +- **Operator associativity**: All binary operators (arithmetic, comparison, logical, `..`) are left-associative. Precedence is described earlier in this document, and also in the [Types](./04_types.md) and [Gotchyas](./07_gotchyas.md) documentation. + +## Type System Details + +- **Type inference**: Type annotations are optional everywhere. They provide runtime validation; without them, code is dynamically typed. +- **Numeric hierarchy**: `Int ⊂ Float ⊂ Number` (widening permitted). +- **Generics**: No type parameters/generics. Achieve polymorphism by leaving parameters unannotated. +- **Type aliases**: Not supported. + +## Advanced Pattern Matching + +- **Nested patterns**: Supported for lists and tables. You can match deep structures, e.g. `{user: {name: "Tziporah"}}`. +- **Pattern Guards**: Use `if` keyword to add conditions to patterns: + ```baba + classify : x -> + when x is + n if (n > 0) then "positive" + n if (n < 0) then "negative" + 0 then "zero"; + ``` +- **Lists/strings**: List patterns match exact shapes (no head/tail cons syntax). Strings can be matched by literal or `String` type. + +## Function Behavior Edge Cases + +- **Partial application**: Supported for all functions; supplying fewer args returns a new function. Supplying more than arity is an error. +- **Recursion optimization**: Tail-call optimization is not performed. +- **Closures and `with`**: + - Functions capture a snapshot of surrounding scope at definition time. + - `with rec` creates function bindings that close over a shared scope (by reference) to enable mutual recursion. + +## Error Handling Patterns + +- **Result chaining**: No built-ins like `andThen`/`mapError`. Idiomatically, compose with helper functions or use nested `when`. +- **Runtime errors**: Thrown as plain errors with standard messages (e.g., `Division by zero`, `Index out of bounds`, `Undefined variable`, `Undefined property`, `Unknown operator`). + +## Performance & Limits + +- **Stack limits**: Recursion depth is limited by the host JS engine’s stack (no TCO). +- **Data sizes**: Lists are JS arrays; tables are proxied maps/objects. Limits are memory-bound. +- **Immutability costs**: Operations return new arrays/maps (no structural sharing). Favor `map`/`filter`/`reduce` and careful composition for large data. |