diff options
Diffstat (limited to 'js/baba-yaga/docs')
-rw-r--r-- | js/baba-yaga/docs/00_crash-course.md | 169 | ||||
-rw-r--r-- | js/baba-yaga/docs/01_functional.md | 130 | ||||
-rw-r--r-- | js/baba-yaga/docs/02_data-structures.md | 85 | ||||
-rw-r--r-- | js/baba-yaga/docs/03_pattern-matching.md | 42 | ||||
-rw-r--r-- | js/baba-yaga/docs/05_recursion-and-composition.md | 82 | ||||
-rw-r--r-- | js/baba-yaga/docs/06_error-handling.md | 632 | ||||
-rw-r--r-- | js/baba-yaga/docs/07_gotchyas.md | 52 | ||||
-rw-r--r-- | js/baba-yaga/docs/08_array-programming.md | 320 | ||||
-rw-r--r-- | js/baba-yaga/docs/09_js-interop.md | 500 | ||||
-rw-r--r-- | js/baba-yaga/docs/README.md | 82 | ||||
-rw-r--r-- | js/baba-yaga/docs/ref.txt | 213 |
11 files changed, 2277 insertions, 30 deletions
diff --git a/js/baba-yaga/docs/00_crash-course.md b/js/baba-yaga/docs/00_crash-course.md index e050973..0327e5e 100644 --- a/js/baba-yaga/docs/00_crash-course.md +++ b/js/baba-yaga/docs/00_crash-course.md @@ -68,7 +68,7 @@ greeting : "Hello"; // Type inferred as String ``` **Type Hierarchy:** -- `Int` ⊂ `Float` ⊂ `Number` (Int can be used where Float expected) +- `Int` ⊂ `Float` ⊂ `Number` (`Int` can be used where `Float` expected) - `String`, `Bool`, `List`, `Table`, `Result` are distinct types ## Functions @@ -482,6 +482,8 @@ processResult : result -> ## 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 -> @@ -658,7 +660,85 @@ 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"; @@ -669,6 +749,68 @@ io.out [1, 2, 3]; 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 @@ -785,10 +927,18 @@ result : processData "20"; // Returns Err "Result too small" (10 is not > 10) - **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) - - **String namespace `str`**: as documented - - **Math namespace `math`**: also includes `sign`, `trunc`, `exp`, `log`, `tan`, `asin`, `acos`, `atan`, `atan2`, `deg`, `rad` - - **IO namespace `io`**: `io.out`, `io.in`, and (host-enabled) event functions `io.emit`, `io.listen` -- also plan to add `io` functions for working with files. + - **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 @@ -806,7 +956,14 @@ result : processData "20"; // Returns Err "Result too small" (10 is not > 10) ## Advanced Pattern Matching - **Nested patterns**: Supported for lists and tables. You can match deep structures, e.g. `{user: {name: "Tziporah"}}`. -- **Guards**: Not supported on patterns; use a `then` expression that evaluates a condition instead. +- **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 diff --git a/js/baba-yaga/docs/01_functional.md b/js/baba-yaga/docs/01_functional.md index 92e7f11..ac8134e 100644 --- a/js/baba-yaga/docs/01_functional.md +++ b/js/baba-yaga/docs/01_functional.md @@ -31,6 +31,37 @@ evens : filter (x -> x % 2 = 0) [1, 2, 3, 4, 5]; // [2, 4] sum : reduce (acc x -> acc + x) 0 [1, 2, 3, 4]; // 10 ``` +## Advanced Data Operations + +Enhanced utilities for sorting and grouping: +```baba +// Custom sorting with key functions +students : [ + {name: "Alice", grade: 85}, + {name: "Bob", grade: 92}, + {name: "Charlie", grade: 78} +]; +byGrade : sort.by students (s -> s.grade); // Sorted by grade: Charlie, Alice, Bob + +// Grouping data by criteria +ages : [18, 25, 17, 30, 16, 45]; +byCategory : group.by ages (age -> + when (age < 18) is + true then "minor" + _ then when (age < 65) is + true then "adult" + _ then "senior" +); +minors : byCategory."minor"; // [17, 16] +adults : byCategory."adult"; // [18, 25, 30, 45] + +// Array processing utilities +data : [1, 2, 3, 4, 5, 6, 7, 8]; +chunks : chunk data 3; // [[1, 2, 3], [4, 5, 6], [7, 8]] +sequence : range 0 4; // [0, 1, 2, 3, 4] +repeated : repeat 3 "x"; // ["x", "x", "x"] +``` + ## Local Bindings with `with` Stage local bindings in a function header right after the arrow. Entries are processed left-to-right in an inner scope. You can type locals using the same style as globals. @@ -99,7 +130,106 @@ math : { resAdd : math.add 2 3; // 5 ``` +## Advanced Array Programming + +Baba Yaga includes powerful array programming features inspired by APL, K, and Q: + +### Scan Operations (Cumulative Operations) +```baba +// General scan operation +numbers : [1, 2, 3, 4, 5]; +addFunc : acc x -> acc + x; +scanned : scan addFunc 0 numbers; // [0, 1, 3, 6, 10, 15] + +// Built-in utilities +cumsum : cumsum numbers; // [0, 1, 3, 6, 10, 15] +cumprod : cumprod numbers; // [1, 1, 2, 6, 24, 120] +``` + +### Advanced Array Indexing +```baba +data : [10, 21, 30, 43, 50]; + +// Select elements at specific indices +indices : [0, 2, 4]; +selected : at indices data; // [10, 30, 50] + +// Find indices where predicate is true +evenPredicate : x -> x % 2 = 0; +evenIndices : where evenPredicate data; // [0, 2, 4] + +// Take and drop elements +firstThree : take 3 data; // [10, 21, 30] +lastTwo : drop 3 data; // [43, 50] +``` + +### Array Broadcasting Operations +```baba +// Broadcast scalar operation over array +addOp : x y -> x + y; +numbers : [1, 2, 3, 4]; +broadcasted : broadcast addOp 10 numbers; // [11, 12, 13, 14] + +// Element-wise operations between arrays +array1 : [1, 2, 3]; +array2 : [10, 20, 30]; +zipped : zipWith addOp array1 array2; // [11, 22, 33] + +// Reshape arrays into matrices +flatArray : [1, 2, 3, 4, 5, 6]; +matrix : reshape [2, 3] flatArray; // 2x3 matrix +``` + +### Enhanced Function Combinators +```baba +// Flip function arguments +add : x y -> x + y; +flippedAdd : flip add; +result : flippedAdd 3 5; // 8 (same as 5 + 3) + +// Apply function to value +double : x -> x * 2; +result : apply double 7; // 14 + +// Pipe value through function (reverse apply) +result : pipe 5 double; // 10 + +// Function composition +increment : x -> x + 1; +composed : compose increment double; +result : composed 4; // 9 (double then increment) +``` + +### Monadic Operations +```baba +// flatMap for flattening mapped results +duplicateFunc : x -> [x, x]; +original : [1, 2, 3]; +duplicated : flatMap duplicateFunc original; // [1, 1, 2, 2, 3, 3] + +// Chain operations that produce lists +rangeFunc : x -> range 1 x; +chained : flatMap rangeFunc [2, 3]; // [1, 2, 1, 2, 3] +``` + +## Pattern Guards + +Pattern matching can be enhanced with conditional guards using the `if` keyword. For detailed documentation and examples, see [Pattern Matching](./03_pattern-matching.md#pattern-guards). + +```baba +// Example: Age categorization with guards +categorizeAge : age -> + when age is + a if (a >= 0 and a < 18) then "minor" + a if (a >= 18 and a < 65) then "adult" + a if (a >= 65) then "senior" + _ then "invalid"; +``` + ## On Style - Prefer small, pure functions - Build complex behavior by composing simple functions +- Use array programming operations for data transformation +- Leverage pattern guards for complex conditional logic +- Combine scan, broadcast, and flatMap for powerful data processing pipelines diff --git a/js/baba-yaga/docs/02_data-structures.md b/js/baba-yaga/docs/02_data-structures.md index ebd39cf..aa41ed9 100644 --- a/js/baba-yaga/docs/02_data-structures.md +++ b/js/baba-yaga/docs/02_data-structures.md @@ -28,11 +28,96 @@ res : calculator.add 10 5; // 15 ``` ## Utilities + +### Core Utilities ```baba length : Built-in; works on lists and strings shape : Built-in; returns a metadata table for lists, strings, tables, scalars ``` +### Array Programming Operations + +Baba Yaga provides powerful array programming operations inspired by APL, K, and Q: + +#### Indexing and Selection +```baba +data : [10, 20, 30, 40, 50]; + +// Select elements at specific indices +selected : at [0, 2, 4] data; // [10, 30, 50] + +// Find indices where predicate is true +evenIndices : where (x -> x % 2 = 0) data; // [0, 1, 2, 3, 4] + +// Take first n elements +firstThree : take 3 data; // [10, 20, 30] + +// Drop first n elements +lastTwo : drop 3 data; // [40, 50] +``` + +#### Cumulative Operations +```baba +numbers : [1, 2, 3, 4, 5]; + +// General scan operation +addFunc : acc x -> acc + x; +scanned : scan addFunc 0 numbers; // [0, 1, 3, 6, 10, 15] + +// Cumulative sum and product utilities +cumSum : cumsum numbers; // [0, 1, 3, 6, 10, 15] +cumProd : cumprod numbers; // [1, 1, 2, 6, 24, 120] +``` + +#### Broadcasting and Element-wise Operations +```baba +values : [1, 2, 3, 4]; + +// Apply scalar operation to each element +addTen : broadcast (x y -> x + y) 10 values; // [11, 12, 13, 14] + +// Element-wise operations on two arrays +array1 : [1, 2, 3]; +array2 : [4, 5, 6]; +multiplied : zipWith (x y -> x * y) array1 array2; // [4, 10, 18] + +// Reshape flat array into matrix +flatData : [1, 2, 3, 4, 5, 6]; +matrix : reshape [2, 3] flatData; // 2x3 matrix +``` + +#### Monadic Operations +```baba +// flatMap for flattening mapped results +duplicator : x -> [x, x]; +original : [1, 2, 3]; +flattened : flatMap duplicator original; // [1, 1, 2, 2, 3, 3] +``` + +### Traditional Data Processing Utilities +```baba +// Array manipulation +numbers : [1, 2, 3, 4, 5, 6]; +grouped : chunk numbers 2; // [[1, 2], [3, 4], [5, 6]] +sequence : range 1 10; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +duplicated : repeat 4 "item"; // ["item", "item", "item", "item"] + +// Sorting and grouping +people : [{name: "Alice", age: 30}, {name: "Bob", age: 25}]; +sorted : sort.by people (p -> p.age); // Sorted by age +grouped : group.by people (p -> p.age > 27); // Group by age criteria + +// Data validation +valid : validate.notEmpty numbers; // true +inRange : validate.range 1 10 5; // true +correctType : validate.type "List" numbers; // true + +// Text processing +text : "hello world example"; +words : text.words text; // ["hello", "world", "example"] +padded : text.padLeft 15 "centered"; // " centered" +``` + ## Shape `shape` returns a metadata table describing the argument. It is similar in spirit to APL's shape (⍴) but returns a table with fields. diff --git a/js/baba-yaga/docs/03_pattern-matching.md b/js/baba-yaga/docs/03_pattern-matching.md index 43c4c65..0bd663e 100644 --- a/js/baba-yaga/docs/03_pattern-matching.md +++ b/js/baba-yaga/docs/03_pattern-matching.md @@ -30,6 +30,48 @@ checkType : val -> _ then "Other"; ``` +## Pattern Guards + +Use the `if` keyword to add conditional guards to patterns: + +```baba +// Basic guards with range conditions +categorizeNumber : n -> + when n is + x if (x > 0) then "positive" + x if (x < 0) then "negative" + 0 then "zero"; + +// Guards with complex conditions +gradeStudent : score -> + when score is + s if (s >= 90) then "A" + s if (s >= 80 and s < 90) then "B" + s if (s >= 70 and s < 80) then "C" + s if (s >= 60 and s < 70) then "D" + s if (s < 60) then "F" + _ then "Invalid score"; + +// Type guards +processValue : value -> + when value is + Int if value > 100 then "large integer" + Int if value > 0 then "positive integer" + String if (length value) > 10 then "long string" + String if (length value) > 0 then "short string" + _ then "other"; + +// Guards with wildcard patterns +checkRange : x -> + when x is + _ if (x >= 1 and x <= 10) then "small" + _ if (x >= 11 and x <= 100) then "medium" + _ if (x > 100) then "large" + _ then "invalid"; +``` + +Guards are evaluated after the underlying pattern matches. The guard expression has access to any variables bound by the pattern. This allows for sophisticated conditional matching without conflicting with the `..` string concatenation operator. + ## Typed discriminants When using typed functions that return `Result`, you can pattern match on variants and bind inner values. diff --git a/js/baba-yaga/docs/05_recursion-and-composition.md b/js/baba-yaga/docs/05_recursion-and-composition.md index 06df31b..0721916 100644 --- a/js/baba-yaga/docs/05_recursion-and-composition.md +++ b/js/baba-yaga/docs/05_recursion-and-composition.md @@ -45,31 +45,26 @@ isEvenOdd : z -> with rec ( ) -> { even: isEven 10, odd: isOdd 7 }; ``` -## Functional Composition (pairwise) +## Function Composition -```baba -// compose f g x = f (g x) -compose : f g x -> f (g x); +Baba Yaga provides built-in function combinators for composition. For detailed documentation, see [Functional Programming](./01_functional.md#function-combinators). +```baba inc : x -> x + 1; double : x -> x * 2; -r1 : compose inc double 3; // inc (double 3) = 7 -r2 : compose double inc 3; // double (inc 3) = 8 -``` - -## Pipeline (left-to-right) - -```baba -// pipe f g x = g (f x) -pipe : f g x -> g (f x); +// Built-in compose (right-to-left): f(g(x)) +composed : compose inc double; +r1 : composed 3; // inc (double 3) = 7 -r3 : pipe inc double 3; // double (inc 3) = 8 +// Built-in pipe (left-to-right): value |> function +r2 : pipe 3 inc; // inc 3 = 4 +r3 : pipe 4 double; // double 4 = 8 ``` ## Composing Many Functions -You can compose an arbitrary list of unary functions using `reduce`. This is likely a more useful version of composition for most scenarios. +You can compose an arbitrary list of unary functions using `reduce`. ```baba // composeAll [f, g, h] = x -> f (g (h x)) @@ -81,4 +76,61 @@ double : x -> x * 2; combo : composeAll [inc, double]; res : combo 3; // inc (double 3) = 7 +``` + +## Recursion with Utility Functions + +Using the enhanced utility functions for recursive algorithms: + +```baba +// Recursive data processing with validation +processNumbers : numbers -> + when (validate.notEmpty numbers) is + false then [] + true then + with ( + sorted : sort.by numbers (x -> x); + chunks : chunk sorted 3; + processed : map (chunk -> reduce (acc x -> acc + x) 0 chunk) chunks; + ) -> + processed; + +// Recursive tree traversal with debugging +traverseTree : tree -> + with rec ( + // Debug each node we visit + visitNode : node -> + when (validate.notEmpty (keys node)) is + false then (debug.print "Empty node"; 0) + true then + with (value : node.value;) -> + (debug.print "Visiting" value; value); + + // Recursive traversal + traverse : node -> + when (validate.notEmpty (keys node)) is + false then 0 + true then + (visitNode node) + + (traverse node.left) + + (traverse node.right); + ) -> + traverse tree; + +// Generate and process sequences recursively +fibonacci : n -> + when (validate.range 0 100 n) is + false then (assert false "n must be 0-100"; 0) + true then + when n is + 0 then 0 + 1 then 1 + _ then (fibonacci (n - 1)) + (fibonacci (n - 2)); + +// Generate fibonacci sequence using range and recursion +fibSequence : count -> + with (indices : range 0 (count - 1);) -> + map fibonacci indices; + +// Example: fibSequence 10 generates [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] ``` \ No newline at end of file diff --git a/js/baba-yaga/docs/06_error-handling.md b/js/baba-yaga/docs/06_error-handling.md new file mode 100644 index 0000000..7bc2a78 --- /dev/null +++ b/js/baba-yaga/docs/06_error-handling.md @@ -0,0 +1,632 @@ +# Error Handling + +Baba Yaga takes a functional approach to error handling, emphasizing explicit error representation and fail-fast programming practices. Instead of exceptions, the language uses the `Result` type for recoverable errors and assertions for programming errors. + +## Philosophy + +- **No Exceptions**: All errors are values that must be handled explicitly +- **Result Type**: Use `Ok`/`Err` variants for operations that might fail +- **Assertions**: Use `assert` for programming errors that should never happen +- **Validation First**: Validate inputs early with the `validate.*` namespace +- **Rich Debugging**: Use `debug.*` tools for development and troubleshooting + +## The Result Type + +The `Result` type represents either success (`Ok value`) or failure (`Err message`). This forces explicit handling of potential failures. + +### Basic Result Usage + +```baba +// Function that might fail +divide : x y -> + when y is + 0 then Err "Division by zero" + _ then Ok (x / y); + +// Using Result with pattern matching +handleDivision : x y -> + when (divide x y) is + Ok result then result + Err message then 0; + +result1 : handleDivision 10 2; // 5 +result2 : handleDivision 10 0; // Returns 0 +``` + +### Result Type Patterns + +```baba +// Parsing with Result +parsePositiveInt : str -> + when str is + "0" then Err "Zero is not positive" + "1" then Ok 1 + "2" then Ok 2 + "5" then Ok 5 + "10" then Ok 10 + _ then Err "Invalid or unsupported number"; + +// Chaining Result operations +processNumber : input -> + when (parsePositiveInt input) is + Err msg then Err msg + Ok num then + when (num > 100) is + true then Err "Number too large" + false then Ok (num * 2); + +// Usage examples +result1 : processNumber "5"; // Ok 10 +result2 : processNumber "0"; // Err "Zero is not positive" +result3 : processNumber "200"; // Err "Number too large" +``` + +## Input Validation + +Use the `validate.*` namespace to check inputs early and prevent errors downstream. + +### Validation Patterns + +```baba +// Basic validation +validateUserInput : input -> + when (validate.notEmpty input) is + false then Err "Input cannot be empty" + true then + when (validate.type "String" input) is + false then Err "Input must be a string" + true then Ok input; + +// Multiple validation checks +validateAge : age -> + when (validate.type "Int" age) is + false then Err "Age must be an integer" + true then + when (validate.range 0 150 age) is + false then Err "Age must be between 0 and 150" + true then Ok age; + +// Email validation +validateEmail : email -> + when (validate.notEmpty email) is + false then Err "Email cannot be empty" + true then + when (validate.email email) is + false then Err "Invalid email format" + true then Ok email; +``` + +### Combining Validations + +```baba +// Validate user registration data +validateUser : userData -> + with ( + nameResult : validateUserInput userData.name; + emailResult : validateEmail userData.email; + ageResult : validateAge userData.age; + ) -> + when nameResult is + Err msg then Err ("Name error: " .. msg) + Ok name then + when emailResult is + Err msg then Err ("Email error: " .. msg) + Ok email then + when ageResult is + Err msg then Err ("Age error: " .. msg) + Ok age then Ok {name: name, email: email, age: age}; + +// Usage +validUser : validateUser {name: "Alice", email: "alice@example.com", age: 25}; +invalidUser : validateUser {name: "", email: "bad-email", age: 200}; +``` + +## Error Chaining and Propagation + +Handle sequences of operations that might fail at any step. + +### Sequential Operations + +```baba +// Chain of operations that might fail +processUserData : rawData -> + when (validateUser rawData) is + Err msg then Err ("Validation failed: " .. msg) + Ok user then + when (checkUserExists user.email) is + Err msg then Err ("User check failed: " .. msg) + Ok exists then + when exists is + true then Err "User already exists" + false then + when (saveUser user) is + Err msg then Err ("Save failed: " .. msg) + Ok savedUser then Ok savedUser; + +// Simulated helper functions +checkUserExists : email -> + when email is + "admin@example.com" then Ok true + _ then Ok false; + +saveUser : user -> + when (validate.notEmpty user.name) is + false then Err "Cannot save user with empty name" + true then Ok user; +``` + +### Error Recovery Strategies + +```baba +// Try multiple approaches +parseNumberWithFallback : input -> + when (parsePositiveInt input) is + Ok num then Ok num + Err _ then + when input is + "zero" then Ok 0 + "one" then Ok 1 + "two" then Ok 2 + _ then Err "Could not parse number"; + +// Provide default values +getConfigValue : key defaultValue -> + when (loadConfig key) is + Ok value then value + Err _ then defaultValue; + +// Simulated config loader +loadConfig : key -> + when key is + "timeout" then Ok 30 + "retries" then Ok 3 + _ then Err "Config key not found"; +``` + +## Assertions vs Results + +Use `assert` for programming errors (bugs) and `Result` for expected failures. + +### When to Use Assert + +```baba +// Programming errors - should never happen in correct code +calculateArea : width height -> + // Assert preconditions + assert (width > 0) "Width must be positive"; + assert (height > 0) "Height must be positive"; + assert (validate.type "Number" width) "Width must be a number"; + assert (validate.type "Number" height) "Height must be a number"; + + width * height; + +// Array bounds checking +getElement : list index -> + assert (validate.type "List" list) "First argument must be a list"; + assert (validate.type "Int" index) "Index must be an integer"; + assert (index >= 0) "Index must be non-negative"; + assert (index < (length list)) "Index out of bounds"; + + list.index; +``` + +### When to Use Result + +```baba +// Expected failures - user input, external resources, business logic +safeGetElement : list index -> + when (validate.type "List" list) is + false then Err "Not a list" + true then + when (validate.type "Int" index) is + false then Err "Index must be integer" + true then + when (validate.range 0 ((length list) - 1) index) is + false then Err "Index out of bounds" + true then Ok list.index; + +// File operations (simulated) +readUserFile : filename -> + when (validate.notEmpty filename) is + false then Err "Filename cannot be empty" + true then + when filename is + "config.txt" then Ok "timeout=30,retries=3" + "users.json" then Ok "Alice" + _ then Err ("File not found: " .. filename); +``` + +## Debugging and Development + +Use the `debug.*` namespace for troubleshooting and development. + +### Debug Printing + +```baba +// Debug intermediate values in error-prone operations +complexCalculation : input -> + with ( + step1 : input * 2; + _ : debug.print "Step1" step1; + step2 : step1 + 10; + _ : debug.print "Step2" step2; + result : step2 / 3; + _ : debug.print "Final" result; + ) -> + result; + +// Debug error paths +parseWithDebug : input -> + debug.print "Parsing input" input; + when (validate.notEmpty input) is + false then + with (_ : debug.print "Empty input detected";) -> + Err "Empty input" + true then + when (parsePositiveInt input) is + Err msg then + with (_ : debug.print "Parse error" msg;) -> + Err msg + Ok result then + with (_ : debug.print "Parse success" result;) -> + Ok result; +``` + +### Value Inspection + +```baba +// Inspect complex data structures during debugging +analyzeUserData : userData -> + with ( + inspection : debug.inspect userData; + _ : debug.print "User data structure:"; + _ : debug.print inspection; + + validation : validateUser userData; + _ : debug.print "Validation result" validation; + ) -> + validation; + +// Debug function behavior +debugFunction : fn input -> + with ( + fnInfo : debug.inspect fn; + _ : debug.print "Function info" fnInfo; + _ : debug.print "Input" input; + + result : fn input; + _ : debug.print "Result" result; + ) -> + result; +``` + +## Real-World Error Handling Patterns + +### Game State Validation + +```baba +// Validate game state for consistency +validateGameState : state -> + with ( + playerValid : when (validate.range 0 100 state.playerHealth) is + false then Err "Player health out of range" + true then Ok state.playerHealth; + + levelValid : when (validate.range 1 10 state.currentLevel) is + false then Err "Invalid level" + true then Ok state.currentLevel; + + inventoryValid : when (validate.notEmpty state.inventory) is + false then Err "Inventory cannot be empty" + true then Ok state.inventory; + ) -> + when playerValid is + Err msg then Err msg + Ok _ then + when levelValid is + Err msg then Err msg + Ok _ then + when inventoryValid is + Err msg then Err msg + Ok _ then Ok state; + +// Game action with error handling +performAction : gameState action -> + when (validateGameState gameState) is + Err msg then Err ("Invalid game state: " .. msg) + Ok validState then + when action is + "heal" then + when (validState.playerHealth < 100) is + false then Err "Player already at full health" + true then Ok (set validState "playerHealth" 100) + "attack" then + when (length validState.inventory > 0) is + false then Err "No weapons available" + true then Ok (set validState "playerHealth" (validState.playerHealth - 10)) + _ then Err ("Unknown action: " .. action); +``` + +### Data Processing Pipeline + +```baba +// Process data through multiple stages with error handling +processDataPipeline : rawData -> + when (validate.notEmpty rawData) is + false then Err "No data to process" + true then + when (cleanData rawData) is + Err msg then Err ("Cleaning failed: " .. msg) + Ok cleaned then + when (transformData cleaned) is + Err msg then Err ("Transform failed: " .. msg) + Ok transformed then + when (validateOutput transformed) is + Err msg then Err ("Validation failed: " .. msg) + Ok validated then Ok validated; + +// Simulated pipeline stages +cleanData : data -> + when (validate.type "List" data) is + false then Err "Data must be a list" + true then + with (filtered : filter (x -> validate.notEmpty x) data;) -> + when (validate.notEmpty filtered) is + false then Err "No valid data after cleaning" + true then Ok filtered; + +transformData : data -> + when (validate.notEmpty data) is + false then Err "Cannot transform empty data" + true then Ok (map (x -> x * 2) data); + +validateOutput : data -> + when (length data < 1) is + true then Err "Output too small" + false then + when (length data > 1000) is + true then Err "Output too large" + false then Ok data; +``` + +### Configuration Loading + +```baba +// Load and validate configuration with fallbacks +loadConfiguration : configFile -> + when (readUserFile configFile) is + Err msg then + debug.print "Config load failed, using defaults" msg; + Ok {timeout: 30, retries: 3, debug: false} + Ok content then + when (parseConfig content) is + Err msg then + debug.print "Config parse failed, using defaults" msg; + Ok {timeout: 30, retries: 3, debug: false} + Ok config then + when (validateConfig config) is + Err msg then Err ("Invalid config: " .. msg) + Ok validConfig then Ok validConfig; + +// Simulated config parsing +parseConfig : content -> + when content is + "timeout=30,retries=3" then Ok {timeout: 30, retries: 3, debug: false} + "timeout=60,retries=5,debug=true" then Ok {timeout: 60, retries: 5, debug: true} + _ then Err "Unrecognized config format"; + +validateConfig : config -> + when (validate.range 1 300 config.timeout) is + false then Err "Timeout must be 1-300 seconds" + true then + when (validate.range 1 10 config.retries) is + false then Err "Retries must be 1-10" + true then Ok config; +``` + +## Error Handling Best Practices + +### 1. Fail Fast with Validation + +```baba +// Good: Validate early +processUser : userData -> + when (validateUser userData) is + Err msg then Err msg + Ok user then expensiveOperation user; + +// Avoid: Validate late +// processUser : userData -> +// result : expensiveOperation userData; +// when (validateUser userData) is +// Err msg then Err msg +// Ok _ then result; +``` + +### 2. Provide Meaningful Error Messages + +```baba +// Good: Specific error messages +validatePassword : password -> + when (validate.notEmpty password) is + false then Err "Password cannot be empty" + true then + when (str.length password < 8) is + true then Err "Password must be at least 8 characters" + false then + when (validate.email password) is + true then Err "Password cannot be an email address" + false then Ok password; + +// Avoid: Generic error messages +// validatePassword : password -> +// when (someValidation password) is +// false then Err "Invalid password" +// true then Ok password; +``` + +### 3. Use Assertions for Programming Errors + +```baba +// Good: Assert impossible conditions +fibonacci : n -> + assert (n >= 0) "Fibonacci input must be non-negative"; + when n is + 0 then 0 + 1 then 1 + _ then (fibonacci (n - 1)) + (fibonacci (n - 2)); + +// Good: Use Result for user errors +safeFibonacci : n -> + when (validate.type "Int" n) is + false then Err "Input must be an integer" + true then + when (validate.range 0 40 n) is + false then Err "Input must be between 0 and 40" + true then Ok (fibonacci n); +``` + +### 4. Debug Complex Error Flows + +```baba +// Use debug.print to trace error paths +complexValidation : data -> + debug.print "Starting validation" data; + + when (validate.notEmpty data) is + false then + with (_ : debug.print "Failed: empty data";) -> + Err "Empty data" + true then + with (_ : debug.print "Passed: not empty";) -> + when (validate.type "List" data) is + false then + with (_ : debug.print "Failed: not a list";) -> + Err "Must be list" + true then + with (_ : debug.print "Passed: is list";) -> + when ((length data) > 100) is + true then + with (_ : debug.print "Failed: too large";) -> + Err "Too large" + false then + with (_ : debug.print "Success: validation complete";) -> + Ok data; +``` + +### 5. Compose Error Handling + +```baba +// Create reusable error handling combinators +mapResult : fn result -> + when result is + Err msg then Err msg + Ok value then Ok (fn value); + +chainResult : fn result -> + when result is + Err msg then Err msg + Ok value then fn value; + +// Compose operations by nesting function calls +processUserChain : userData -> + mapResult saveUser + (chainResult checkUserExists + (chainResult validateUser + (Ok userData))); + +// Or use intermediate variables for clarity +processUserStep : userData -> + with ( + step1 : chainResult validateUser (Ok userData); + step2 : chainResult checkUserExists step1; + step3 : mapResult saveUser step2; + ) -> + step3; +``` + +## Summary + +Baba Yaga's error handling approach emphasizes: + +1. **Explicit Error Values**: Use `Result` type instead of exceptions +2. **Early Validation**: Check inputs with `validate.*` functions +3. **Clear Distinction**: `assert` for bugs, `Result` for expected failures +4. **Rich Debugging**: Use `debug.*` tools during development +5. **Meaningful Messages**: Provide specific, actionable error information +6. **Composition**: Chain operations while preserving error information + +This approach leads to more robust, predictable code where error handling is an explicit part of the program's logic rather than an afterthought. + +## Array Programming Error Handling + +Array programming operations include specific error cases that should be handled appropriately: + +### Index Bounds Errors +```baba +// Safe array access with bounds checking +safeAt : indices data -> + with ( + validIndices : filter (i -> i >= 0 and i < length data) indices; + ) -> when (length validIndices = length indices) is + true then Ok (at validIndices data) + _ then Err "One or more indices out of bounds"; + +// Usage +data : [1, 2, 3]; +result1 : safeAt [0, 2] data; // Ok [1, 3] +result2 : safeAt [0, 5] data; // Err "One or more indices out of bounds" +``` + +### Reshape Dimension Errors +```baba +// Safe reshape with dimension validation +safeReshape : dimensions flatArray -> + with ( + totalElements : reduce (acc x -> acc * x) 1 dimensions; + arrayLength : length flatArray; + ) -> when (totalElements = arrayLength) is + true then Ok (reshape dimensions flatArray) + _ then Err ("Cannot reshape array of length " .. arrayLength .. " to dimensions " .. dimensions); + +// Usage +data : [1, 2, 3, 4, 5, 6]; +result1 : safeReshape [2, 3] data; // Ok (2x3 matrix) +result2 : safeReshape [2, 4] data; // Err "Cannot reshape array of length 6 to dimensions [2, 4]" +``` + +### Function Type Validation +```baba +// Validate function arguments for array operations +safeScan : func initial array -> + when func is + Function then Ok (scan func initial array) + _ then Err "scan expects a function as first argument"; + +// Usage +addFunc : acc x -> acc + x; +numbers : [1, 2, 3]; +result1 : safeScan addFunc 0 numbers; // Ok [0, 1, 3, 6] +result2 : safeScan 42 0 numbers; // Err "scan expects a function as first argument" +``` + +### Negative Count Validation +```baba +// Safe take/drop with non-negative validation +safeTake : n array -> + when n is + count if (count >= 0) then Ok (take count array) + _ then Err "take expects a non-negative number"; + +safeDrop : n array -> + when n is + count if (count >= 0) then Ok (drop count array) + _ then Err "drop expects a non-negative number"; + +// Usage +data : [1, 2, 3, 4, 5]; +result1 : safeTake 3 data; // Ok [1, 2, 3] +result2 : safeTake -1 data; // Err "take expects a non-negative number" +``` + +These patterns demonstrate how to wrap array programming operations in safe functions that return `Result` types, allowing graceful error handling in data processing pipelines. diff --git a/js/baba-yaga/docs/07_gotchyas.md b/js/baba-yaga/docs/07_gotchyas.md index bf8b300..dc71b38 100644 --- a/js/baba-yaga/docs/07_gotchyas.md +++ b/js/baba-yaga/docs/07_gotchyas.md @@ -11,6 +11,7 @@ This document catalogs the strict syntax requirements and common pitfalls discov 5. [Function Definitions](#function-definitions) 6. [Data Structure Syntax](#data-structure-syntax) 7. [Common Error Patterns](#common-error-patterns) +8. [JavaScript Interop Gotchas](#javascript-interop-gotchas) ## When Expression Syntax @@ -230,14 +231,14 @@ isValid and hasData; // Error: Unexpected token: KEYWORD (and) ### **Critical Rule: Complex Comparison Chains** -** Incorrect: Complex comparisons without parentheses** +**Incorrect: Complex comparisons without parentheses** ```baba // WRONG - Complex comparisons need parentheses math.abs (x * x + y * y) - (z * z) < 0.001; // Error: Unexpected token: OPERATOR (-) side1 + side2 > side3; // Error: Unexpected token: OPERATOR (>) ``` -** Correct: Complex comparisons wrapped in parentheses** +**Correct: Complex comparisons wrapped in parentheses** ```baba // CORRECT - Wrap complex comparisons in parentheses (math.abs ((x * x + y * y) - (z * z))) < 0.001; // ✓ Works correctly @@ -516,12 +517,13 @@ For comprehensive information about Baba Yaga's type system, see: - **[Types Documentation](./04_types.md)** - Complete type system reference - **[Recursion Documentation](./05_recursion-and-composition.md)** - Details on `with rec` usage - **[Crash Course](./00_crash-course.md)** - Examples and patterns +- **[JavaScript Interop](./09_js-interop.md)** - Complete JS interop reference ## Common Error Patterns ### 1. **Unexpected SEMICOLON errors** -- **Cause**: Missing semicolon after when expressions in with blocks -- **Solution**: Always add semicolon after each with block entry +- **Cause**: Missing semicolon after `when` expressions in `with` blocks +- **Solution**: Always add semicolon after each `with` block entry ### 2. **Unexpected COLON errors** - **Cause**: Incorrect table literal syntax @@ -549,7 +551,7 @@ For comprehensive information about Baba Yaga's type system, see: - Always use `_ then` for fallback cases - Use `then when` for nested conditions - Wrap complex conditions in parentheses -- Add semicolons after when expressions in with blocks +- Add semicolons after when expressions in `with` blocks ### 2. **With vs With Rec** - **Use `with`** for: @@ -571,11 +573,10 @@ For comprehensive information about Baba Yaga's type system, see: ### 4. **Type System** - Use simple type declarations: `x Int; x : 5;` - Avoid function type annotations -- Use documented functions only ### 5. **Data Structures** -- Use explicit key: value pairs in tables -- Use when expressions for conditional access +- Use explicit `key: value` pairs in tables +- Use `when` expressions for conditional access - Avoid dynamic property access ## Debugging Tips @@ -605,4 +606,37 @@ For comprehensive information about Baba Yaga's type system, see: - Wrap function calls in comparisons: `(length list) > 0` - Wrap logical expressions: `(a > 0) and (b > 0)` - Wrap complex arithmetic: `(x + y) > z` -- See [Operator Precedence Rules](#operator-precedence-and-parenthesization-rules) for details \ No newline at end of file +- See [Operator Precedence Rules](#operator-precedence-and-parenthesization-rules) for details + +## JavaScript Interop Gotchas + +When working with JavaScript interop, there are some specific gotchas to be aware of: + +### **JSValue Wrapper Behavior** + +```baba +// WRONG - Expecting direct value access +result : io.callJS "Math.abs" [-42]; +value : result.value; // This is a JSValue wrapper, not the raw number + +// CORRECT - Pass JSValue directly to other io.* functions +result : io.callJS "Math.abs" [-42]; +when result is + Ok jsValue then io.objectToTable jsValue // JSValue accepted directly + Err msg then Err msg; +``` + +### **Type Conversion Timing** + +```baba +// WRONG - Premature conversion can lose JS semantics +parsed : io.callJS "JSON.parse" [jsonString]; +table : when parsed is + Ok jsValue then io.objectToTable jsValue; // Converts immediately + +// CORRECT - Keep as JSValue until needed +parsed : io.callJS "JSON.parse" [jsonString]; +// Work with JSValue directly, convert only when needed +``` + +For comprehensive JavaScript interop documentation, see [JavaScript Interop](./09_js-interop.md). \ No newline at end of file diff --git a/js/baba-yaga/docs/08_array-programming.md b/js/baba-yaga/docs/08_array-programming.md new file mode 100644 index 0000000..1fb3fcd --- /dev/null +++ b/js/baba-yaga/docs/08_array-programming.md @@ -0,0 +1,320 @@ +# Array Programming + +Baba Yaga provides powerful array programming operations inspired by APL, K, and Q languages. These operations enable concise, expressive data transformations and mathematical computations on arrays. + +## Philosophy + +Array programming treats data as multidimensional arrays and provides operations that work on entire arrays at once, rather than element-by-element processing. This leads to: + +- **Concise Code**: Express complex operations in single function calls +- **Mathematical Clarity**: Operations mirror mathematical notation +- **Performance**: Operations are optimized for bulk data processing +- **Composability**: Operations chain together naturally + +## Indexing and Selection Operations + +### `at` - Select by Indices +Select elements from an array at specific positions: + +```baba +data : [10, 20, 30, 40, 50]; +indices : [0, 2, 4]; +selected : at indices data; // [10, 30, 50] + +// Empty indices return empty array +empty : at [] data; // [] + +// Out of bounds indices throw errors +// invalid : at [0, 10] data; // Error: Index out of bounds +``` + +### `where` - Find by Predicate +Find indices where a predicate function returns true: + +```baba +data : [10, 21, 30, 43, 50]; +evenPredicate : x -> x % 2 = 0; +evenIndices : where evenPredicate data; // [0, 2, 4] + +// Find all elements greater than 25 +largePredicate : x -> x > 25; +largeIndices : where largePredicate data; // [2, 3, 4] + +// No matches return empty array +neverTrue : x -> false; +empty : where neverTrue data; // [] +``` + +### `take` - First N Elements +Take the first n elements from an array: + +```baba +data : [1, 2, 3, 4, 5, 6]; +firstThree : take 3 data; // [1, 2, 3] +firstZero : take 0 data; // [] +all : take 10 data; // [1, 2, 3, 4, 5, 6] (all available) + +// Negative numbers throw errors +// invalid : take -1 data; // Error: take expects non-negative number +``` + +### `drop` - Remove First N Elements +Remove the first n elements from an array: + +```baba +data : [1, 2, 3, 4, 5, 6]; +lastThree : drop 3 data; // [4, 5, 6] +none : drop 10 data; // [] (dropped more than available) +all : drop 0 data; // [1, 2, 3, 4, 5, 6] (no change) + +// Negative numbers throw errors +// invalid : drop -1 data; // Error: drop expects non-negative number +``` + +## Cumulative Operations (Scan) + +### `scan` - General Cumulative Operation +Apply a binary function cumulatively across an array: + +```baba +// Custom scan with addition +addFunc : acc x -> acc + x; +numbers : [1, 2, 3, 4, 5]; +cumulative : scan addFunc 0 numbers; // [0, 1, 3, 6, 10, 15] + +// Scan with multiplication +mulFunc : acc x -> acc * x; +products : scan mulFunc 1 numbers; // [1, 1, 2, 6, 24, 120] + +// Scan with string concatenation +concatFunc : acc x -> acc .. x; +words : ["hello", " ", "world"]; +sentence : scan concatFunc "" words; // ["", "hello", "hello ", "hello world"] +``` + +### `cumsum` - Cumulative Sum +Specialized scan for addition (most common use case): + +```baba +numbers : [1, 2, 3, 4, 5]; +cumSums : cumsum numbers; // [0, 1, 3, 6, 10, 15] + +// Equivalent to: scan (acc x -> acc + x) 0 numbers +``` + +### `cumprod` - Cumulative Product +Specialized scan for multiplication: + +```baba +numbers : [1, 2, 3, 4, 5]; +cumProducts : cumprod numbers; // [1, 1, 2, 6, 24, 120] + +// Equivalent to: scan (acc x -> acc * x) 1 numbers +``` + +## Broadcasting Operations + +### `broadcast` - Scalar-Array Operations +Apply a binary operation between a scalar and each array element: + +```baba +values : [1, 2, 3, 4]; +addOp : x y -> x + y; +addTen : broadcast addOp 10 values; // [11, 12, 13, 14] + +// Subtraction +subOp : x y -> x - y; +subtract5 : broadcast subOp 5 values; // [-4, -3, -2, -1] (5 - each element) + +// Division +divOp : x y -> x / y; +reciprocals : broadcast divOp 1 values; // [1, 0.5, 0.333..., 0.25] +``` + +### `zipWith` - Element-wise Binary Operations +Apply a binary operation element-wise to two arrays: + +```baba +array1 : [1, 2, 3, 4]; +array2 : [10, 20, 30, 40]; + +// Element-wise addition +addOp : x y -> x + y; +sums : zipWith addOp array1 array2; // [11, 22, 33, 44] + +// Element-wise multiplication +mulOp : x y -> x * y; +products : zipWith mulOp array1 array2; // [10, 40, 90, 160] + +// Arrays of different lengths use minimum length +short : [1, 2]; +long : [10, 20, 30, 40]; +result : zipWith addOp short long; // [11, 22] +``` + +### `reshape` - Array Restructuring +Reshape a flat array into a multidimensional structure: + +```baba +flatData : [1, 2, 3, 4, 5, 6]; + +// Reshape into 2x3 matrix +matrix2x3 : reshape [2, 3] flatData; // 2 rows, 3 columns +// Result: [[1, 2, 3], [4, 5, 6]] + +// Reshape into 3x2 matrix +matrix3x2 : reshape [3, 2] flatData; // 3 rows, 2 columns +// Result: [[1, 2], [3, 4], [5, 6]] + +// Incompatible dimensions throw errors +// invalid : reshape [2, 4] flatData; // Error: Cannot reshape array of length 6 to [2, 4] +``` + +## Monadic Operations + +### `flatMap` - Map and Flatten +Apply a function that returns arrays, then flatten the results: + +```baba +// Duplicate each element +duplicator : x -> [x, x]; +original : [1, 2, 3]; +duplicated : flatMap duplicator original; // [1, 1, 2, 2, 3, 3] + +// Generate ranges +rangeFunc : x -> range 1 x; +ranges : flatMap rangeFunc [2, 3]; // [1, 2, 1, 2, 3] + +// Filter and transform +evenDoubles : x -> when x % 2 is 0 then [x * 2] _ then []; +numbers : [1, 2, 3, 4, 5]; +result : flatMap evenDoubles numbers; // [4, 8] +``` + +## Array Programming Patterns + +### Data Pipeline Processing +```baba +// Process sales data: filter, transform, aggregate +salesData : [100, 250, 75, 300, 150, 400, 50]; + +pipeline : data -> + with ( + // Find high-value sales (>= 200) + highValueIndices : where (x -> x >= 200) data; + highValues : at highValueIndices data; + + // Apply discount + discounted : broadcast (x y -> x * y) 0.9 highValues; + + // Calculate cumulative revenue + cumulativeRevenue : cumsum discounted; + ) -> { + original: highValues, + discounted: discounted, + cumulative: cumulativeRevenue, + total: (slice cumulativeRevenue (length cumulativeRevenue - 1) (length cumulativeRevenue)).0 + }; + +result : pipeline salesData; +``` + +### Matrix Operations +```baba +// Create and manipulate matrices +flatMatrix : [1, 2, 3, 4, 5, 6, 7, 8, 9]; +matrix3x3 : reshape [3, 3] flatMatrix; + +// Add scalar to all elements +addOp : x y -> x + y; +shifted : broadcast addOp 10 flatMatrix; +shiftedMatrix : reshape [3, 3] shifted; + +// Element-wise operations between matrices +matrix2 : [9, 8, 7, 6, 5, 4, 3, 2, 1]; +mulOp : x y -> x * y; +elementwiseProduct : zipWith mulOp flatMatrix matrix2; +productMatrix : reshape [3, 3] elementwiseProduct; +``` + +### Statistical Analysis +```baba +// Statistical operations on datasets +dataset : [23, 45, 67, 12, 89, 34, 56, 78, 90, 11]; + +analyze : data -> + with ( + sorted : sort.by data (x -> x); + n : length data; + + // Cumulative statistics + cumSums : cumsum data; + runningAverages : broadcast (x y -> x / y) (cumsum data) (range 1 (n + 1)); + + // Percentile indices + q1Index : (n + 1) / 4; + q3Index : 3 * (n + 1) / 4; + ) -> { + size: n, + total: (slice cumSums (n - 1) n).0, + runningAvgs: runningAverages, + sorted: sorted + }; + +stats : analyze dataset; +``` + +## Error Handling + +Array programming operations include comprehensive error checking: + +```baba +// Index out of bounds +data : [1, 2, 3]; +// error : at [0, 5] data; // Error: Index out of bounds + +// Invalid reshape dimensions +flatData : [1, 2, 3, 4, 5]; +// error : reshape [2, 3] flatData; // Error: Cannot reshape array of length 5 to [2, 3] + +// Type errors +// error : scan "not a function" 0 [1, 2, 3]; // Error: Scan expects a function +// error : broadcast 42 5 [1, 2, 3]; // Error: broadcast expects a function +``` + +## Performance Considerations + +- **Bulk Operations**: Array programming operations are optimized for processing entire arrays +- **Memory Efficiency**: Operations create new arrays (immutable) but reuse underlying data when possible +- **Composition**: Chain operations together for complex transformations without intermediate variables +- **Functional Style**: Pure functions with no side effects enable optimizations + +## Integration with Other Features + +Array programming operations integrate seamlessly with other Baba Yaga features: + +```baba +// With pattern matching +processArray : arr -> + when (length arr) is + 0 then [] + 1 then arr + n if (n > 10) then take 10 arr // Limit large arrays + _ then broadcast (x y -> x + y) 1 arr; // Add 1 to each element + +// With error handling using Result types +safeAt : indices data -> + when (filter (i -> i >= 0 and i < length data) indices) is + validIndices then Ok (at validIndices data) + _ then Err "Invalid indices"; + +// With higher-order functions +applyToColumns : matrix func -> + with ( + rows : length matrix; + cols : length matrix.0; + columnData : i -> map (row -> row.i) matrix; + ) -> map (i -> func (columnData i)) (range 0 cols); +``` + +Array programming in Baba Yaga provides a powerful, expressive way to work with collections of data, enabling both mathematical computations and practical data processing tasks. diff --git a/js/baba-yaga/docs/09_js-interop.md b/js/baba-yaga/docs/09_js-interop.md new file mode 100644 index 0000000..28ec7bb --- /dev/null +++ b/js/baba-yaga/docs/09_js-interop.md @@ -0,0 +1,500 @@ +# JavaScript Interop + +This document covers Baba Yaga's JavaScript interoperability features, which allow safe and controlled access to JavaScript functionality while maintaining Baba Yaga's functional programming guarantees. + +## Table of Contents + +1. [Overview](#overview) +2. [Core Functions](#core-functions) +3. [Type Conversion](#type-conversion) +4. [Security Model](#security-model) +5. [Common Patterns](#common-patterns) +6. [Error Handling](#error-handling) +7. [Configuration](#configuration) +8. [Best Practices](#best-practices) +9. [Examples](#examples) + +## Overview + +Baba Yaga's JavaScript interop system provides a safe bridge between Baba Yaga's functional, immutable world and JavaScript's imperative, mutable one. All JavaScript operations return `Result` types to maintain explicit error handling. + +### Key Principles + +- **Safety First**: All JS operations are sandboxed and return `Result` types +- **Explicit Boundaries**: Clear separation between Baba Yaga and JavaScript +- **Type Safety**: Automatic conversion between type systems +- **Error Isolation**: JavaScript errors become Baba Yaga `Err` values + +## Core Functions + +All JavaScript interop functions are available in the `io.*` namespace. + +### Function Calls + +#### `io.callJS` +Call a JavaScript function synchronously. + +```baba +io.callJS : (functionName: String, args: [Any]) -> Result + +// Examples +absResult : io.callJS "Math.abs" [-42]; +// Returns: Ok (JSValue 42) + +parseResult : io.callJS "JSON.parse" ["{\"x\": 10}"]; +// Returns: Ok (JSValue {x: 10}) + +// Note: io.callJS returns a Result whose Ok value is a JSValue wrapper +// around the raw JavaScript value. You can pass this JSValue directly to +// io.getProperty, io.setProperty, io.hasProperty, io.jsArrayToList, +// io.objectToTable, etc. without manual unwrapping. +``` + +#### `io.callJSAsync` +Call a JavaScript function asynchronously (if async operations are enabled). + +```baba +io.callJSAsync : (functionName: String, args: [Any]) -> Result + +// Example (requires enableAsyncOps: true) +fetchResult : io.callJSAsync "fetch" ["https://api.example.com/data"]; +``` + +### Property Access + +#### `io.getProperty` +Get a property from a JavaScript object. + +```baba +io.getProperty : (obj: Any, propName: String) -> Result + +// Example +obj : io.callJS "JSON.parse" ["{\"name\": \"Alice\"}"]; +nameResult : when obj is + Ok parsed then io.getProperty parsed "name" + Err msg then Err msg; +// Returns: Ok "Alice" (direct Baba Yaga string) +``` + +#### `io.setProperty` +Set a property on a JavaScript object (mutates the object). + +```baba +io.setProperty : (obj: Any, propName: String, value: Any) -> Result + +// Example +obj : io.callJS "JSON.parse" ["{}"]; +result : when obj is + Ok parsed then io.setProperty parsed "newProp" 42 + Err msg then Err msg; +``` + +#### `io.hasProperty` +Check if a property exists on a JavaScript object. + +```baba +io.hasProperty : (obj: Any, propName: String) -> Bool + +// Example +obj : io.callJS "JSON.parse" ["{\"x\": 10}"]; +hasX : when obj is + Ok parsed then io.hasProperty parsed "x" + Err _ then false; +// Returns: true +``` + +### Type Conversion + +#### `io.jsArrayToList` +Convert a JavaScript array to a Baba Yaga list. + +```baba +io.jsArrayToList : (jsArray: Any) -> Result + +// Example +jsArray : io.callJS "JSON.parse" ["[1, 2, 3]"]; +listResult : when jsArray is + Ok arr then io.jsArrayToList arr + Err msg then Err msg; +// Returns: Ok [1, 2, 3] (direct Baba Yaga list) +``` + +#### `io.listToJSArray` +Convert a Baba Yaga list to a JavaScript array. + +```baba +io.listToJSArray : (list: [Any]) -> Any + +// Example +babaList : [1, 2, 3, 4, 5]; +jsArray : io.listToJSArray babaList; +jsonResult : io.callJS "JSON.stringify" [jsArray]; +// Returns: Ok (JSValue "[1,2,3,4,5]") +``` + +#### `io.objectToTable` +Convert a JavaScript object to a Baba Yaga table. + +```baba +io.objectToTable : (obj: Any) -> Result + +// Example +jsObj : io.callJS "JSON.parse" ["{\"name\": \"Bob\", \"age\": 25}"]; +tableResult : when jsObj is + Ok obj then io.objectToTable obj + Err msg then Err msg; +// Returns: Ok {name: "Bob", age: 25} (direct Baba Yaga table) +``` + +#### `io.tableToObject` +Convert a Baba Yaga table to a JavaScript object. + +```baba +io.tableToObject : (table: Table) -> Any + +// Example +babaTable : {x: 100, y: 200}; +jsObj : io.tableToObject babaTable; +jsonResult : io.callJS "JSON.stringify" [jsObj]; +// Returns: Ok (JSValue "{\"x\":100,\"y\":200}") +``` + +### Error Management + +#### `io.getLastJSError` +Get the last JavaScript error that occurred. + +Note: depending on language syntax rules for zero-argument functions, direct invocation may not be available in all contexts. Prefer handling errors from `io.callJS` directly via the returned `Result`. + +#### `io.clearJSError` +Clear the last JavaScript error. + +Note: same invocation caveat as above applies. + +## Type Conversion + +### Automatic Conversions + +The JavaScript bridge automatically converts between Baba Yaga and JavaScript types: + +| Baba Yaga Type | JavaScript Type | Notes | +|----------------|-----------------|-------------------------------------| +| `Number` | `number` | Preserves integer/float distinction | +| `String` | `string` | Direct conversion | +| `Bool` | `boolean` | Direct conversion | +| `List` | `Array` | Recursive conversion of elements | +| `Table` | `Object` | Converts Map to plain object | +| `Result` | N/A | Handled at boundary | + + +### Manual Conversions + +For more control, use explicit conversion functions: + +```baba +// Safe JSON parsing with error handling +parseJSON : jsonString -> + when (validate.type "String" jsonString) is + false then Err "Input must be a string" + true then when (io.callJS "JSON.parse" [jsonString]) is + Ok parsed then Ok (io.objectToTable parsed) + Err msg then Err ("JSON parse error: " .. msg); + +// Usage +result : parseJSON "{\"user\": \"Alice\", \"score\": 95}"; +``` + +## Security Model + +The JavaScript interop system uses a configurable security model: + +### Sandboxed Execution + +All JavaScript code runs in a controlled sandbox with: + +- **Limited Global Access**: Only allowed globals are available +- **Function Whitelist**: Only explicitly allowed functions can be called +- **Timeout Protection**: Operations have configurable time limits +- **Memory Limits**: Configurable memory usage constraints + +### Default Allowed Functions + +By default, these JavaScript functions are available: + +```javascript +// JSON operations +'JSON.parse', 'JSON.stringify', + +// Math operations +'Math.abs', 'Math.floor', 'Math.ceil', 'Math.round', +'Math.min', 'Math.max', 'Math.random', + +// Console operations +'console.log', 'console.warn', 'console.error', + +// Time operations +'Date.now', 'performance.now' +``` + +### Configuration + +Configure the JavaScript bridge through the host configuration: + +```javascript +const host = { + jsBridgeConfig: { + allowedFunctions: new Set(['Math.abs', 'JSON.parse']), + maxExecutionTime: 5000, // 5 seconds + enableAsyncOps: false, // Disable async operations + enableFileSystem: false, // Disable file system access + enableNetwork: false // Disable network access + } +}; +``` + +## Common Patterns + +### Safe JSON Operations + +```baba +// Safe JSON parsing +safeParseJSON : jsonStr -> + when (io.callJS "JSON.parse" [jsonStr]) is + Ok obj then when (io.objectToTable obj) is + Ok table then Ok table + Err msg then Err ("Conversion error: " .. msg) + Err msg then Err ("Parse error: " .. msg); + +// Safe JSON stringification +safeStringifyJSON : table -> + jsObj : io.tableToObject table; + io.callJS "JSON.stringify" [jsObj]; +``` + +### Mathematical Operations + +```baba +// Safe mathematical operations with validation +safeMath : operation args -> + when (validate.notEmpty args) is + false then Err "No arguments provided" + true then when operation is + "abs" then io.callJS "Math.abs" [head args] + "min" then io.callJS "Math.min" args + "max" then io.callJS "Math.max" args + "round" then io.callJS "Math.round" [head args] + _ then Err ("Unknown operation: " .. operation); + +// Usage +result : safeMath "abs" [-42]; // Ok 42 +minResult : safeMath "min" [10, 5, 8]; // Ok 5 +``` + +### Working with JavaScript APIs + +```baba +// Date operations +getCurrentTimestamp : () -> + io.callJS "Date.now" []; + +formatDate : timestamp -> + when (io.callJS "Date" [timestamp]) is + Ok dateObj then io.callJS "Date.prototype.toISOString" [dateObj] + Err msg then Err msg; + +// Performance monitoring +measurePerformance : operation -> + startTime : io.callJS "performance.now" []; + result : operation; + endTime : io.callJS "performance.now" []; + + duration : when (startTime, endTime) is + (Ok start, Ok end) then Ok (end - start) + _ then Err "Could not measure performance"; + + {result: result, duration: duration}; +``` + +## Error Handling + +### JavaScript Error Types + +JavaScript errors are automatically converted to Baba Yaga `Err` values: + +```baba +// This will return an Err +result : io.callJS "JSON.parse" ["invalid json"]; +// Returns: Err "Unexpected token i in JSON at position 0" + +// Handle different error types +handleJSError : result -> + when result is + Ok value then processValue value + Err msg then when (text.contains msg "JSON") is + true then handleJSONError msg + false then handleGenericError msg; +``` + +### Error Recovery Patterns + +```baba +// Retry pattern +retryOperation : operation maxAttempts -> + attempt : 1; + + tryOperation : currentAttempt -> + when (currentAttempt > maxAttempts) is + true then Err "Max attempts exceeded" + false then when (operation) is + Ok result then Ok result + Err _ then tryOperation (currentAttempt + 1); + + tryOperation attempt; + +// Fallback pattern +withFallback : primaryOp fallbackOp -> + when primaryOp is + Ok result then Ok result + Err _ then fallbackOp; +``` + +## Best Practices + +### 1. Always Use Result Types + +Never assume JavaScript operations will succeed: + +```baba +// Good +result : when (io.callJS "Math.abs" [value]) is + Ok abs then processValue abs + Err msg then handleError msg; + +// Bad - assumes success +abs : io.callJS "Math.abs" [value]; // This returns Result, not number +``` + +### 2. Validate Inputs + +Always validate data before sending to JavaScript: + +```baba +// Good +safeCall : value -> + when (validate.type "Number" value) is + false then Err "Value must be a number" + true then io.callJS "Math.abs" [value]; + +// Bad - no validation +unsafeCall : value -> + io.callJS "Math.abs" [value]; +``` + +### 3. Handle Type Conversions Explicitly + +Be explicit about type conversions: + +```baba +// Good +processJSData : jsData -> + when (io.objectToTable jsData) is + Ok table then processTable table + Err msg then Err ("Conversion failed: " .. msg); + +// Bad - assumes conversion works +processJSData : jsData -> + table : io.objectToTable jsData; + processTable table; +``` + +### 4. Use Composition for Complex Operations + +Break complex JavaScript interactions into smaller, composable functions: + +```baba +// Composed operations +parseAndValidate : jsonStr schema -> + parsed : safeParseJSON jsonStr; + when parsed is + Ok data then validateAgainstSchema data schema + Err msg then Err msg; + +transformAndStringify : data transformer -> + transformed : transformer data; + safeStringifyJSON transformed; +``` + +## Examples + +### Complete JSON Processing Pipeline + +```baba +// Complete JSON processing with error handling +processJSONData : jsonString -> + // Parse JSON + parseResult : io.callJS "JSON.parse" [jsonString]; + + when parseResult is + Err msg then Err ("Parse failed: " .. msg) + Ok jsObj then + // Convert to Baba Yaga table + when (io.objectToTable jsObj) is + Err msg then Err ("Conversion failed: " .. msg) + Ok table then + // Process the data + processedTable : processData table; + + // Convert back to JS object + jsResult : io.tableToObject processedTable; + + // Stringify result + io.callJS "JSON.stringify" [jsResult]; + +// Helper function +processData : table -> + // Add timestamp + withTimestamp : table .. {timestamp: getCurrentTimestamp}; + + // Validate required fields + when (hasRequiredFields withTimestamp) is + false then table .. {error: "Missing required fields"} + true then withTimestamp; + +// Usage +input : "{\"name\": \"Alice\", \"score\": 95}"; +result : processJSONData input; +// Returns: Ok (JSValue "{\"name\":\"Alice\",\"score\":95,\"timestamp\":1640995200000}") +``` + +### Working with JavaScript Arrays + +```baba +// Process JavaScript arrays +processJSArray : jsArrayString -> + // Parse array + arrayResult : io.callJS "JSON.parse" [jsArrayString]; + + when arrayResult is + Err msg then Err msg + Ok jsArray then + // Convert to Baba Yaga list + when (io.jsArrayToList jsArray) is + Err msg then Err msg + Ok babaList then + // Process with Baba Yaga functions + processed : map (x -> x * 2) babaList; + filtered : filter (x -> x > 10) processed; + + // Convert back to JS array + jsResult : io.listToJSArray filtered; + + // Return as JSON + io.callJS "JSON.stringify" [jsResult]; + +// Usage +input : "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"; +result : processJSArray input; +// Returns: Ok (JSValue "[4,6,8,10,12,14,16,18,20]") +``` + +This JavaScript interop system provides a safe, controlled way to leverage JavaScript's ecosystem while maintaining Baba Yaga's functional programming principles and explicit error handling. diff --git a/js/baba-yaga/docs/README.md b/js/baba-yaga/docs/README.md new file mode 100644 index 0000000..30f8700 --- /dev/null +++ b/js/baba-yaga/docs/README.md @@ -0,0 +1,82 @@ +# Baba Yaga Documentation + +This directory contains comprehensive documentation for the Baba Yaga functional programming language. + +## Documentation Structure + +### Core Documentation + +- **[00_crash-course.md](./00_crash-course.md)** - Complete language overview for quick reference (ideal for LLMs and quick onboarding) +- **[01_functional.md](./01_functional.md)** - Functional programming concepts, higher-order functions, and function combinators +- **[02_data-structures.md](./02_data-structures.md)** - Lists, tables, and array programming operations +- **[03_pattern-matching.md](./03_pattern-matching.md)** - Pattern matching syntax, guards, and advanced patterns +- **[04_types.md](./04_types.md)** - Optional type system, runtime validation, and type inference +- **[05_recursion-and-composition.md](./05_recursion-and-composition.md)** - Recursive functions, mutual recursion, and function composition +- **[06_error-handling.md](./06_error-handling.md)** - Result types, assertions, validation, and error handling patterns +- **[07_gotchyas.md](./07_gotchyas.md)** - Common syntax pitfalls and strict requirements +- **[08_array-programming.md](./08_array-programming.md)** - Comprehensive guide to array programming operations +- **[09_js-interop.md](./09_js-interop.md)** - JavaScript interoperability and safe JS integration + +## Topic Coverage + +### Language Fundamentals +- **Syntax**: Variables, functions, data types, operators (00, 07) +- **Data Types**: Numbers, strings, booleans, lists, tables (00, 02) +- **Functions**: Anonymous functions, currying, partial application (00, 01) +- **Control Flow**: `when` expressions, pattern matching (00, 03) + +### Advanced Features +- **Pattern Matching**: Literals, wildcards, types, guards, multiple discriminants (03) +- **Type System**: Optional types, runtime validation, function signatures (04) +- **Error Handling**: Result types, assertions, validation patterns (06) +- **Recursion**: Simple, tail, and mutual recursion (05) + +### Functional Programming +- **Higher-Order Functions**: `map`, `filter`, `reduce` (01) +- **Function Combinators**: `flip`, `apply`, `pipe`, `compose` (01) +- **Array Programming**: Indexing, scanning, broadcasting, reshaping (02, 08) +- **Monadic Operations**: `flatMap` and data transformation (01, 02, 08) + +### Standard Library +- **Array Operations**: `scan`, `cumsum`, `at`, `where`, `take`, `drop`, `broadcast`, `zipWith`, `reshape` (02, 08) +- **Math Functions**: Arithmetic, trigonometry, random numbers (00) +- **String Processing**: Manipulation, formatting, validation (00) +- **Utilities**: Sorting, grouping, debugging, validation (00, 06) +- **JavaScript Interop**: Safe JS function calls, property access, type conversion (09) + +## Documentation Principles + +1. **Non-Duplicative**: Each concept is documented in one primary location with cross-references +2. **Comprehensive**: All language features and standard library functions are covered +3. **Hierarchical**: Start with crash course, then dive into specific topics +4. **Practical**: Includes working examples and common patterns +5. **Error-Aware**: Documents error cases and safe usage patterns + +## Reading Path + +### For New Users +1. [Crash Course](./00_crash-course.md) - Complete overview +2. [Functional Programming](./01_functional.md) - Core concepts +3. [Data Structures](./02_data-structures.md) - Working with data +4. [Pattern Matching](./03_pattern-matching.md) - Control flow + +### For Specific Topics +- **Array Processing**: [Data Structures](./02_data-structures.md) → [Array Programming](./08_array-programming.md) +- **Advanced Functions**: [Functional Programming](./01_functional.md) → [Recursion & Composition](./05_recursion-and-composition.md) +- **Robust Code**: [Error Handling](./06_error-handling.md) → [Types](./04_types.md) +- **Troubleshooting**: [Gotchas](./07_gotchyas.md) +- **JavaScript Integration**: [JavaScript Interop](./09_js-interop.md) + +### For LLMs and Quick Reference +- [Crash Course](./00_crash-course.md) provides complete context in a single document + +## Cross-References + +Documentation includes appropriate cross-references to avoid duplication: +- Pattern guards are detailed in [Pattern Matching](./03_pattern-matching.md), referenced in [Functional Programming](./01_functional.md) +- Function combinators are detailed in [Functional Programming](./01_functional.md), referenced in [Recursion & Composition](./05_recursion-and-composition.md) +- Array programming is covered in both [Data Structures](./02_data-structures.md) (overview) and [Array Programming](./08_array-programming.md) (comprehensive) +- Error handling patterns for array operations are in [Error Handling](./06_error-handling.md) +- JavaScript interop strategies and gotchas are in [JavaScript Interop](./09_js-interop.md), with basic gotchas in [Gotchas](./07_gotchyas.md) + +This structure ensures comprehensive coverage while maintaining clarity and avoiding redundancy. diff --git a/js/baba-yaga/docs/ref.txt b/js/baba-yaga/docs/ref.txt new file mode 100644 index 0000000..88320fe --- /dev/null +++ b/js/baba-yaga/docs/ref.txt @@ -0,0 +1,213 @@ +BABA YAGA LANGUAGE REFERENCE +============================ + +SYNTAX +------ +var : value; // assignment +var Type; var : value; // typed assignment +f : x -> body; // function +f : x y -> body; // multi-param function +f : (x: Type) -> Type -> body; // typed function +f : x -> y -> body; // curried function +f : x -> with (locals) -> body; // with locals +f : x -> with rec (fns) -> body;// with mutual recursion + +LITERALS +-------- +42 // Int +3.14 // Float +"text" // String +true false // Bool +[1,2,3] // List +{a:1, b:2} // Table +PI INFINITY // constants + +OPERATORS (precedence high→low) +------------------------------- +f x, obj.prop // call, access +- ! // unary minus, not +* / % // multiply, divide, modulo ++ - // add, subtract += != < <= > >= // comparison +and or // logical +.. // string concat + +CONTROL FLOW +------------ +when x is // pattern match + 0 then "zero" + Int then "number" + _ then "other"; + +when x y is // multi-discriminant + 0 0 then "origin" + _ _ then "other"; + +x if (condition) then result // pattern guard +_ then "fallback"; + +TYPES +----- +Int Float Number String Bool List Table Result Function + +Int ⊂ Float ⊂ Number // type hierarchy +Ok value | Err message // Result variants + +ARRAY OPERATIONS +---------------- +// Core HOFs +map f xs // [f x | x <- xs] +filter p xs // [x | x <- xs, p x] +reduce f z xs // f(...f(f(z,x1),x2)...,xn) + +// Array programming +scan f z xs // cumulative reduce +cumsum xs // cumulative sum +cumprod xs // cumulative product +at indices xs // xs[indices] +where p xs // indices where p x is true +take n xs // first n elements +drop n xs // drop first n elements +broadcast f scalar xs // f scalar to each x +zipWith f xs ys // [f x y | (x,y) <- zip xs ys] +reshape dims xs // reshape flat array to matrix +flatMap f xs // concat (map f xs) + +// List manipulation +append xs x // xs ++ [x] +prepend x xs // [x] ++ xs +concat xs ys // xs ++ ys +update xs i x // xs with xs[i] = x +removeAt xs i // xs without xs[i] +slice xs start end // xs[start:end] +length xs // |xs| + +// Utilities +chunk xs n // split xs into chunks of size n +range start end // [start..end] +repeat n x // [x,x,...] (n times) +sort.by xs f // sort xs by key function f +group.by xs f // group xs by key function f + +TABLE OPERATIONS +---------------- +set tbl k v // tbl with tbl[k] = v +remove tbl k // tbl without tbl[k] +merge tbl1 tbl2 // tbl1 ∪ tbl2 +keys tbl // [k | k <- tbl] +values tbl // [tbl[k] | k <- tbl] +shape x // metadata: kind, rank, shape, size + +STRING OPERATIONS +----------------- +str.concat s1 s2 ... // s1 + s2 + ... +str.split s delim // split s by delim +str.join xs delim // join xs with delim +str.length s // |s| +str.substring s start end // s[start:end] +str.replace s old new // replace old with new in s +str.trim s // strip whitespace +str.upper s // uppercase +str.lower s // lowercase +text.lines s // split by newlines +text.words s // split by whitespace + +MATH OPERATIONS +--------------- +// Arithmetic +math.abs x // |x| +math.sign x // -1, 0, or 1 +math.min x y, math.max x y // min/max +math.clamp x lo hi // clamp x to [lo,hi] + +// Rounding +math.floor x, math.ceil x // ⌊x⌋, ⌈x⌉ +math.round x, math.trunc x // round, truncate + +// Powers & logs +math.pow x y // x^y +math.sqrt x // √x +math.exp x, math.log x // e^x, ln(x) + +// Trigonometry +math.sin x, math.cos x, math.tan x +math.asin x, math.acos x, math.atan x, math.atan2 y x +math.deg x, math.rad x // degrees ↔ radians + +// Random +math.random // [0,1) +math.randomInt lo hi // [lo,hi] + +FUNCTION COMBINATORS +-------------------- +flip f // λx y. f y x +apply f x // f x +pipe x f // f x (reverse apply) +compose f g // λx. f (g x) (binary compose) + +VALIDATION & DEBUG +------------------ +// Validation +validate.notEmpty x // x is not empty +validate.range lo hi x // lo ≤ x ≤ hi +validate.type "Type" x // x has type Type +validate.email x // x is valid email + +// Debugging +debug.print [name] value // print with optional name +debug.inspect x // detailed inspection +assert condition message // throw if condition false + +I/O +--- +io.out value // print value +io.in // read stdin + +JAVASCRIPT INTEROP +------------------ +io.callJS fnName args // call JS function synchronously +io.callJSAsync fnName args // call JS function asynchronously +io.getProperty obj propName // get JS object property +io.setProperty obj propName val // set JS object property +io.hasProperty obj propName // check if JS property exists +io.jsArrayToList jsArray // convert JS array to Baba Yaga list +io.listToJSArray list // convert Baba Yaga list to JS array +io.objectToTable jsObj // convert JS object to Baba Yaga table +io.tableToObject table // convert Baba Yaga table to JS object +io.getLastJSError // get last JS error (if available) +io.clearJSError // clear last JS error (if available) + +EXAMPLES +-------- +// Fibonacci +fib : n -> when n is 0 then 0 1 then 1 _ then (fib (n-1)) + (fib (n-2)); + +// Array processing pipeline +process : xs -> + with ( + filtered : filter (x -> (x % 2) = 0) xs; + doubled : map (x -> x * 2) filtered; + summed : reduce (acc x -> acc + x) 0 doubled; + ) -> summed; + +// Result handling +safeDivide : x y -> when y is 0 then Err "div by zero" _ then Ok (x / y); +use : r -> when r is Ok v then v Err _ then 0; + +// Pattern matching with guards +classify : x -> when x is + n if ((n > 0) and (n < 10)) then "small positive" + n if (n >= 10) then "large positive" + n if (n < 0) then "negative" + _ then "zero"; + +// Mutual recursion +evenOdd : n -> with rec ( + even : x -> when x is 0 then true _ then odd (x - 1); + odd : x -> when x is 0 then false _ then even (x - 1); +) -> {even: even n, odd: odd n}; + +// Array programming +matrix : reshape [2,3] [1,2,3,4,5,6]; // [[1,2,3],[4,5,6]] +indices : where (x -> x > 3) [1,2,3,4,5]; // [3,4] +selected : at indices [10,20,30,40,50]; // [40,50] \ No newline at end of file |