Introduction :article ARTICLE

An introductory overview of Lava's modern scripting approach, covering its key benefits and comparisons.

Lava: A Modern, Modular Scripting Language

Lava is a lightweight, expressive scripting language designed to handle anything from simple file operations to more intricate data processing or networking tasks. Its focus on clarity, modularity, and developer-friendly features makes it well-suited for rapid development while preserving efficiency.

Key Strengths & Features

Live REPL & Interactive Development

Lava supports real-time experimentation and incremental coding without restarts, thanks to its robust REPL.

Partial Usage & Composition

By allowing partial application and easy function composition, Lava fosters concise patterns in everyday scripting.

Typed Arrays & Implicit Upcasting

Lava offers specialized array types (int, float, keyed, etc.) and automatically upcasts elements to float if a single float is present, simplifying mixed numeric operations.

Dynamic Bridging & Extensibility

At runtime, Lava can load shared libraries to integrate system-level functions or third-party code, enabling powerful modular development.

Poller-Based Concurrency

Lava uses pollers instead of traditional threads, keeping complexity low and offering a clean event-loop style for asynchronous tasks.

Comparisons with Other Languages

Lava vs. Python

While Python is recognized for its extensive standard library, Lava’s partial application, implicit typing, and typed arrays can provide more streamlined solutions in data-heavy tasks.

Lava vs. JavaScript / Node.js

Though Node.js also uses an event loop, Lava’s poller system and upcasting arrays can lead to cleaner, safer concurrency patterns and numeric handling.

Lava vs. Other Scripting Options

Lava emphasizes composition and bridging, creating a concise but extensible environment that is easy to adopt for both small scripts and larger modular designs.

Operators in Lava :core ARTICLE

Overview of the logical, comparison, and arithmetic operators recognized by the Lava parser.

Lava’s parser supports a range of unary and binary operators. Below is a summary, grouped by category. Expressions can use parentheses `(...)` to override normal precedence.

1) **Arithmetic Operators**

- `+` (addition): e.g. `a + b`.

- `-` (subtraction or unary negation): e.g. `a - b`, or `-x` for negative.

- `*` (multiplication): e.g. `a * b`.

- `/` (division): e.g. `a / b`. (Typically yields float results, but bridging can vary.)

- `%` (modulo): e.g. `a % b` for remainder.

2) **Comparison Operators** (result in boolean `true`/`false`)

- `==` (equality check).

- `!=` (inequality).

- `<` (less than).

- `<=` (less or equal).

- `>` (greater than).

- `>=` (greater or equal).

3) **Logical (Boolean) Operators**

- `&&` (logical AND): short-circuits if left side is false.

- `||` (logical OR): short-circuits if left side is true.

- `!` (logical NOT): unary operator, e.g. `!x`.

4) **Bitwise Operators** (operate on integer operands)

- `&` (bitwise AND).

- `|` (bitwise OR).

- `^` (bitwise XOR).

- `~` (bitwise NOT / complement).

- `<<` (left shift).

- `>>` (right shift).

5) **Precedence Overview** (from highest to lowest)

- Parentheses `( ... )` override everything.

- Unary operators `-` (negation), `!`, `~` (applied to a single operand).

- Multiplicative `*`, `/`, `%`.

- Additive `+`, `-` (binary subtraction).

- Shifts `<<`, `>>`.

- Relational / comparison `<`, `>`, `<=`, `>=`, `==`, `!=`.

- Bitwise AND `&`, then XOR `^`, then OR `|`.

- Logical AND `&&`, then logical OR `||`.

Notes: Lava’s parser2 internally defines a parsing order for these operations. You can also chain operations, respecting precedence, or use parentheses for clarity. Placeholders `_` can still appear in expressions but are not themselves an operator—they enable partial application.

abs :math Math JSMath

Returns the absolute value of a single numeric argument.
extend("math") sput( math:abs(-42) ) # => 42 sput( math:abs(3.14) ) # => 3.14

Accepts exactly 1 numeric argument (int, float, or something coercible).

Returns the absolute value as an int or float, depending on your environment’s bridging.

If called with non-numeric or multiple arguments, it raises an error.

acos :math Math JSMath

Computes the arccosine (in radians) of a single numeric argument between -1 and 1.
extend("math") sput( math:acos(1) ) # => 0.0 sput( math:acos(0) ) # => ~1.57079632679 # Raises an error if the argument is out of range or not numeric.

Takes exactly 1 argument in the domain [-1, 1]. Returns the angle in radians.

If called with an out-of-range value, it may return NaN or raise an error (implementation-dependent).

acosh :math Math JSMath

Computes the inverse hyperbolic cosine of a numeric argument ≥ 1.
extend("math") sput( math:acosh(1) ) # => 0 sput( math:acosh(10) ) # => ~2.99822295029797

Accepts exactly 1 argument >= 1. If you pass a smaller number, it may raise an error or return NaN (depending on bridging).

Returns a float representing acosh(value).

add :gpu GPU PARTIAL

Performs elementwise addition of two tensors on the GPU, returning a new tensor with the same shape. If GPU path is missing, it may fallback to CPU.
extend("gpu") # 1) Basic usage => shapes must match A = gpu:to_tensor([[1,2],[3,4]]) B = gpu:to_tensor([[5,6],[7,8]]) C = gpu:add(A, B) slog(gpu:to_array(C)) # => [[6.0,8.0],[10.0,12.0]] # 2) Partial usage => known B, missing A addB = gpu:add(_, B) res = addB(A) slog(gpu:to_array(res)) # => [[6.0,8.0],[10.0,12.0]] # 3) Shape mismatch => error => e.g. 2×2 plus 2×3 => bridging raises an error. # 4) If the real GPU path isn't implemented, logs "real GPU path not implemented => fallback CPU".

Takes exactly two 2D tensors of the same shape. The result is elementwise A[i] + B[i].

Partial usage is supported (gpu:add(A) => function expecting B).

If dimension mismatch or bridging detects an invalid shape, an error is raised. If GPU is not available, logs fallback usage and calculates on CPU.

add :matrix Matrix PARTIAL

Matrix addition of two 2D matrix arrays
extend("matrix") A = [[1,2],[3,4]] B = [[5,6],[7,8]] sum = matrix:add(A,B) # => [[6,8],[10,12]] # Partial usage addA = matrix:add(A) addA(B) # [[6,8],[10,12]] # Placeholder partialAdd = matrix:add(_, B) partialAdd(A) # => [[6,8],[10,12]]

Accepts up to two arguments (A, B). If both are given, it returns A+B only one is given, it returns a partial function waiting for the missing array.

Each argument must be either int2d_array or float2d_array of matching dimensions. If they differ in shape or if either is not 2D, an error is raised.

If one array is float2d and the other is int2d, both get upcast to float2d internally (depending on bridging).

Raises an error if dimension mismatch or if either argument is not recognized as int2d or float2d.

all :test TestUtility ASYNC

Runs all discovered .mu test files in alphabetical order, calling a callback for each file’s pass/fail status.
extend("test") test:all(() => {})

Takes exactly 1 argument: a callback function that receives pass/fail status after each test file completes or a final outcome (environment-dependent).

Internally calls `test:list()` to discover .mu files, then calls `test:run(file, cb)` for each, sorting the results so failing tests might appear last or in a certain order.

Use this as a single entry point to run all your test files from a script or CI environment. If you prefer to run them individually, call `test:run(...)` for each file.

append :array Array PARTIAL

Appends a single item to an existing array (or concatenates strings). Supports partial usage with placeholders.
extend("array") // Direct usage sput( array:append(99, [10,20,30]) ) // => [10,20,30,99] // Partial usage => supply only the item addX = array:append("X") sput( addX(["A","B"]) ) // => ["A","B","X"] // If the second argument is a single string, the item must be a single string => concatenation

Accepts up to two arguments: (item, arrayOrString).

If array is int[], item must be an int. If array is str[], item must be a single string, etc.

If the 'array' is actually a single string, then item must also be a single string, and the result is a concatenation of those two strings.

Missing arguments or placeholders create a partial usage scenario.

apply :array Array PARTIAL

Calls a function with the elements of an array as individual arguments. Partial usage is supported for the function or the array.
extend("array") # Basic usage: sput( array:apply((x,y) => x + y, [10,20]) ) # => 30 # If the array has 3 elements: sput( array:apply((a,b,c)=> a * b * c, [2,3,4]) ) # => 24 # If the array is empty => calls (fn) with no arguments. sput( array:apply(() => "no args!", []) ) # => "no args!" # Partial usage => missing the array: f = array:apply((x,y,z) => x + y + z) # f is a partial function waiting for an array: sput( f([1,2,3]) ) # => 6 # Placeholder usage => known array, missing function: partial = array:apply(_, [7,8]) sput( partial((x,y)=> x - y) ) # => -1

Expects up to two arguments: (function, array). If both are provided, it calls function(...arrElements).

If the array has `n` elements, they become `n` arguments to the function. If it’s empty, the function is called with zero arguments.

Partial usage: If you only supply one argument or placeholders, it returns a partial function waiting for the missing piece. Example: `array:apply((a,b))` => returns a partial needing an array.

If the second argument is not recognized as an array (int[], str[], bool[], float[]), it raises an error.

Similar to Ramda’s `apply(fn, arr) => fn(...arr)` pattern.

apply_activation :gpu GPU

Applies a specified activation function (e.g., 'relu', 'sigmoid', 'tanh') elementwise to a tensor on the GPU.
extend("gpu") A = gpu:to_tensor([[1.0,-2.0],[3.0,-4.5]]) B = gpu:apply_activation("relu", A) # => [[1.0,0.0],[3.0,0.0]] sput(B) C = gpu:apply_activation("sigmoid", A) # => each element => 1 / (1 + exp(-x)) # Use cases: # 1) Neural network forward pass for hidden layers. # 2) Custom elementwise activation in GPU-based data pipelines.

gpu:apply_activation expects 2 arguments: (Str activationName, Tensor).

Supported strings might be 'relu', 'sigmoid', 'tanh', or others depending on bridging. If unknown, raises an error.

Returns a new tensor of the same shape, with each element replaced by the activation function result.

arb :math Arithmetic ArbPrec

Evaluates a custom string expression with arbitrary-precision decimal arithmetic.
extend("math") # Basic usage: pass a string with an expression. sput( math:arb("0.1 + 0.2") ) # => "0.3" sput( math:arb("(1.5 - 0.5) * 10") ) # => "10.0" # Negative numbers sput( math:arb("(-1.2 + 0.2) * 10") ) # => "-10.0" # Large or integer math sput( math:arb("123456789 * 987654321") ) # => "121932631112635269" # For invalid syntax or if you pass multiple arguments, math:arb raises an error.

math:arb(...) parses the given string expression (like "0.1 + 0.2") and calculates the result using a custom decimal approach for exact arithmetic, avoiding floating-point rounding issues.

Supported operators include +, -, *, and /, along with parentheses. Division uses a fixed internal precision (e.g. 20 digits).

Accepts exactly one argument: a single string representing the expression. If you pass something else (like multiple strings or an array), it raises an error.

Returns the final decimal result as a single string, e.g. "0.3" or "121932631112635269".

asin :math Math JSMath

Returns the arcsine of a single numeric argument in [-1,1], result in radians.
extend("math") sput( math:asin(0) ) # => 0 sput( math:asin(1) ) # => ~1.57079632679

One argument only, must be in the domain [-1,1].

Returns a float in the range [-π/2, π/2].

asinh :math Math JSMath

Computes the inverse hyperbolic sine of a numeric argument.
extend("math") sput( math:asinh(0) ) # => 0 sput( math:asinh(1) ) # => ~0.881373

Accepts 1 numeric argument of any real value.

Returns a float representing asinh(x).

assoc :array Array PARTIAL

Sets or updates a key-value pair in a keyed array, returning a new keyed array. Supports placeholders for key, value, or object.
extend("array") keyed = [ name:"Alice" ] sput( array:assoc("city", "London", keyed) ) // => [ name:"Alice", city:"London" ] # Partial usage setter = array:assoc("color", "blue") sput( setter(keyed) ) // => [ name:"Alice", color:"blue" ] # Placeholder usage bananaSetter = array:assoc(_, "banana", keyed) sput( bananaSetter("fruit") ) // => [ name:"Alice", fruit:"banana" ]

Expects (key, value, object). The object must be a KeyedArray. The key must be a single string. If the key already exists, its value is replaced.

If you only supply (key, value), it returns a partial function waiting for the object. If you skip any of them with `_`, it returns a partial needing more calls.

Raises an error if the object is not keyed or if the key is invalid.

atan :math Math JSMath

Computes the arctangent (in radians) of a single numeric argument.
extend("math") sput( math:atan(1) ) # => ~0.78539816339 sput( math:atan(0) ) # => 0

One argument only, any real number.

Returns the angle in radians in range (-π/2, π/2).

atan2 :math Math JSMath PARTIAL

Returns the angle in radians between the positive x-axis and the point (x,y). Takes two numeric arguments, y and x. Partial usage is available.
extend("math") # Direct usage sput( math:atan2(1, 1) ) # => ~0.78539816339 # Partial usage => supply just one argument myAtan2y5 = math:atan2(5) # => function waiting for x sput( myAtan2y5(0) ) # => ~1.57079632679 (90 degrees) # Or skip the first param with underscore: atX0 = math:atan2(_, 0) sput( atX0(1) ) # => ~1.57079632679

Takes two arguments: (y, x). If only one is provided (or placeholders used), partial usage applies.

atan2 returns a float angle in radians, range (-π, π).

atanh :math Math JSMath

Computes the inverse hyperbolic tangent of a numeric argument in the range (-1,1).
extend("math") sput( math:atanh(0) ) # => 0 sput( math:atanh(0.5) ) # => ~0.549306144334

Accepts 1 numeric argument strictly between -1 and 1 for finite real results.

If out of range or exactly ±1, might produce error or Infinity/NaN (depending on bridging).

cbrt :math Math JSMath

Returns the cube root of a single numeric argument.
extend("math") sput( math:cbrt(8) ) # => 2 sput( math:cbrt(-27) ) # => -3

Takes 1 numeric argument, which can be negative or positive.

Returns the real cube root as a float.

ceil :math Math JSMath

Rounds a single numeric argument up to the nearest integer, returning a float or int.
extend("math") sput( math:ceil(3.14) ) # => 4 sput( math:ceil(-2.1) ) # => -2

One numeric argument only. Returns the smallest integer ≥ value (some bridging may store it as float).

clz32 :math Math JSMath

Counts leading zero bits in the 32-bit unsigned integer representation of the argument.
extend("math") sput( math:clz32(1) ) # => 31 sput( math:clz32(1000) ) # => 22

Takes 1 numeric argument, converts it to a 32-bit unsigned integer, then counts the leading zero bits in its binary form.

If the argument is 0 or not numeric, the result might be 32 or bridging error for invalid input.

command :sys System ASYNC

Runs a shell command asynchronously and immediately returns `Bool(true)`. The result is eventually passed to a callback as a keyed array containing the command's output, error stream, exit code, etc.
// Basic usage: extend("sys") // Launch an external command asynchronously. sys:command("echo 'Hello'", result => { // 'result' is a keyed array. // For example: [ command:"echo 'Hello'", stdout:"Hello ", stderr:"", exit:0, success:true ] // Print the type => typically "keyed_array". sput( type(result) ) // Print the entire keyed array. sput(result) }) // The interpreter's main loop (or plugin tasks) will keep running // until any background tasks complete, so your callback can finish.

sys:command(...) spawns a background thread to run the given command string in your system shell/environment.

The second argument is a callback function that receives a keyed array when the command finishes. That array typically has these fields:

- `command`: the original command string

- `stdout`: a single string of the command's stdout output

- `stderr`: a single string of the command's stderr output

- `exit`: an integer exit code (0 means success, non-zero means error)

- `success`: a boolean true if exit=0, false otherwise

You do not have to return anything from your callback function. The `sys:command` call returns `Bool(true)` immediately, while the command runs in the background.

If you need to actively poll for how many sys:command tasks remain, call `sys:check_tasks()` repeatedly. In some Lava builds, a built-in event loop runs that automatically waits for tasks to finish before exiting.

compose :core Core PARTIAL

Combines multiple functions right-to-left, returning a single function. The output of one function is passed as the input to the next.
############################################ # Example usage of compose(...) ############################################ # 1) Suppose we have some functions: # string:upper => converts a single string to uppercase # string:length => returns the length of a single string # plus(10) => adds 10 to a number extend("string") extend("array") # 2) We create a composition using compose: # The data flows from right to left. # So we first call string:length on the input, # then add 10, then sput will receive that final result. myComp = compose( sput, plus(10), string:length ) # 3) Now we can call 'myComp' with a single argument. # Because of composition’s right-to-left flow: # - The argument goes to string:length # - The result of that goes to plus(10) # - Finally, that goes into sput. myComp("hello") # => 15 (because "hello" is length 5, plus 10 => 15)

compose(...) processes arguments from the rightmost function to the leftmost, similar to how nested function calls work: f(g(h(x))).

If you need left-to-right ordering, see pipe(...).

You can partially apply compose by providing fewer arguments, using underscore placeholders for the missing function slots. Once all slots are known, it yields a single function that you can invoke with your data.

compose :flow Flow PARTIAL

Chains multiple transform functions from right-to-left, returning a single function that processes data when finally called.
extend("flow") # 1) Basic usage with multiple transforms => right-to-left chain = flow:compose( flow:trans(x => x * 10), flow:trans(x => x + 1) ) # chain => partial => we can call chain(...) with an InkIterator out = chain( ink(1,5) ) res = flow:to_array(out) # => for each item in [1..4], step1 => x+1 => [2..5], step2 => x*10 => [20..50]. sput(res) # 2) Possibly placeholders => fill them in future calls p = flow:compose( _, flow:trans(x => x - 1) ) # Then pass the missing transform later. finalComp = p(flow:trans(x => x+100)) # Now finalComp => we can call with ink(...) => items processed from right to left.

flow:compose(...) can take any number of function arguments. Each must be either a bridging or user function returning an InkTransform if you want to chain them. However, it does not strictly require them to be transforms; it composes the calls from right to left.

If all arguments are real functions, it returns a final function. If placeholders or partial usage is detected, it returns a partial function waiting for the missing pieces.

Once fully formed, calling the final composition with a single data value (like an InkIterator) passes that data through each function from right to left. The rightmost function is called first, then its result is fed into the next, etc.

concat :array Array PARTIAL

Concatenates two arrays (of the same element type) end-to-end, returning a new array. Supports partial usage for either argument.
extend("array") # 1) Basic usage => combine two integer arrays: sput( array:concat([1,2,3], [4,5]) ) # => [1,2,3,4,5] # 2) Partial usage => known first array, missing second: partialConcat = array:concat([10,20]) sput( partialConcat([30,40,50]) ) # => [10,20,30,40,50] # 3) Placeholder => known second array, missing first: knownTail = array:concat(_, ["X","Y"]) sput( knownTail(["A"]) ) # => ["A","X","Y"] # 4) If the arrays differ in type (like int[] vs str[]), bridging may raise an error or coerce them, depending on your environment.

Accepts up to two arguments => (array1, array2). If both are provided, returns a single array containing all elements of array1 followed by all elements of array2.

If either argument is missing or a placeholder (_), partial usage is returned, waiting for the missing piece.

Typically both arrays must be of the same element type. Some builds might attempt to unify or raise an error if types differ.

concat :string String PARTIAL

Concatenates two strings, supporting partial usage and underscore placeholders for either argument
extend("string") # 1) Direct usage: Provide both parameters now result = string:concat("Hello, ", "World!") sput(result) // => "Hello, World!" # 2) Partial usage: Provide only the first parameter myConcat = string:concat("abc") resultA = myConcat("def") sput(resultA) // => "abcdef" resultB = myConcat("xyz") sput(resultB) // => "abcxyz" # 3) Partial usage with underscore placeholder for the first parameter myConcat2 = string:concat(_, "World!") sput( myConcat2("Hello, ") ) // => "Hello, World!" sput( myConcat2("Greetings, ") ) // => "Greetings, World!"

Only accepts two string parameters in total.

Allows partial application if one argument is omitted or uses underscore (_).

Once both strings are known, it returns a single concatenated string.

cos :math Math JSMath

Returns the cosine (in radians) of a single numeric argument.
extend("math") sput( math:cos(0) ) # => 1.0 sput( math:cos(3.14159) ) # => ~-1.0

One argument only. Interpreted as radians. Returns a float cos(x).

cosh :math Math JSMath

Computes the hyperbolic cosine of a single numeric argument.
extend("math") sput( math:cosh(0) ) # => 1 sput( math:cosh(1) ) # => ~1.54308063482

Single numeric argument. Returns cosh(x) as a float.

create :kanvas Kanvas PARTIAL

Creates a new window for drawing graphics, with configurable size, title, and flags.
extend("kanvas") win = kanvas:create([ title: "Hello, Lava + minifb", width: 800, height: 600, borderless: false, resize: false, scale: "X1", # options: X1, X2, X4, X8 scaleMode: "UpperLeft", # options: Stretch, Center, UpperLeft topmost: false, transparency: false ])

The function takes a single keyed array with window options:

- `title`: Window title (string)

- `width`, `height`: Dimensions in pixels (int)

- `borderless`, `resize`, `topmost`, `transparency`: Boolean flags

- `scale`: String, controls upscaling ('X1', 'X2', etc.)

- `scaleMode`: Placement/scaling style ('UpperLeft', 'Stretch', etc.)

Returns a window handle to be used in later Kanvas calls.

Partial usage may be available if not all options are supplied (implementation-dependent).

decode :json JSON PARTIAL

Parses a JSON string (or reads from an InkIterator / InkTransform of character codes / string chunks) and converts it into a Lava Value.
extend("json") # 1) Decode a simple JSON string data = json:decode('{"name":"Alice","age":30}') sput(data) # => [ name:"Alice", age:30 ] (a keyed_array) # 2) Partial usage => no arguments yet myPartial = json:decode() result = myPartial('{"ok":true}') sput(result) # => [ ok:true ] # 3) Decoding from an InkIterator of ASCII char codes iter = ink(91, 92, 93) # i.e. ASCII for '[' ']' or any chunk sput( json:decode(iter) ) # 4) If your transform yields text fragments or char codes, json:decode can gather them until done. # 5) Common return types: # - bool, int, float, single-string, keyed_array, int_array, float_array, str_array, etc.

Takes exactly 1 argument if fully applied, which can be: - A single string (like '{"key":"value"}'), - A StrArray of length 1 (treated as a single JSON string), - An InkIterator or InkTransform producing ASCII characters or string chunks. If you call `json:decode()` with no arguments, it returns a partial function waiting for that argument.

On success, returns a Lava `Value` that matches the JSON structure (bool, int, float, KeyedArray, etc.). Null is converted to a placeholder `_` by default (or whichever bridging logic you configured).

If the JSON is invalid, an error is raised. If reading from an InkIterator or Transform, we gather characters until EOF or an error occurs.

describe :test Testing Suite

Groups a set of test cases under a named suite, then calls the provided callback to define them.
extend("test") describe("1+1", () => { it("should be 2", () => { expect_equal( 1 + 1, 2 ) }) })

The first argument is a descriptive string name for the test suite.

The second argument is a callback function that contains one or more 'it(...)' calls defining actual tests.

If any assertions fail within that callback, an error is raised and the current test or suite may halt.

display :kanvas Kanvas

Displays (shows) a Kanvas window previously created by kanvas:create.
extend("kanvas") win = kanvas:create([ title: "Show me!", width: 400, height: 300 ]) kanvas:display(win)

Takes a window handle returned by kanvas:create.

Shows the window. Must be called before drawing functions take effect.

Typically returns a boolean or success indicator.

divide :math Math PARTIAL

Divides one numeric value (or array) by another, returning a float or float array. Supports partial usage and underscore placeholders.
extend("math") # 1) Basic usage => single numbers sput( math:divide(10, 2) ) # => 5.0 (float) # 2) Partial usage => known numerator, missing denominator divBy5 = math:divide(_, 5) sput( divBy5(100) ) # => 20.0 # 3) If one argument is an array, element-wise division occurs: # All results are float arrays. sput( math:divide([10,20,30], 10) ) # => [1.0,2.0,3.0] sput( math:divide(20, [2,5]) ) # => [10.0,4.0] # 4) Division by zero => error or Infinity, depending on bridging. # Negative zeros or NaN might occur if your environment supports them.

Expects up to 2 arguments => (numerator, denominator). If either is missing or _, partial usage is returned until both are known.

All operations produce float or float[] results. For integer arrays, bridging typically converts them to float arrays before division.

Division by zero raises an error or returns Infinity, depending on your bridging logic.

If the arrays differ in length (for array/array division), bridging raises an error in most builds.

each :array Array PARTIAL Effect

Applies a function to each item in an array for side effects and returns the original array unchanged.
extend("array") # Straight usage array:each(sput, [1,2,3]) // returns [1,2,3] // outputs 123 # Partial usage printAll = array:each(sput) printAll([4,5,6]) // outputs 456 # Placeholder partial usage runner = array:each(_, ["A","B"]) runner(sput) // outputs AB

Similar to array:map but calls the function for the purpose of side effects, then returns the original array as-is.

encode :json JSON PARTIAL

Converts a Lava Value into a JSON string. The first argument is a KeyedArray of options (required), the second is the data.
extend("json") # 1) Basic usage => encode a keyed array: js = json:encode([ pretty:true ], [ name:"Alice", age:30 ]) sput(js) # => prints something like: # { # "name": "Alice", # "age": 30 # } # 2) Using indent => place a custom indentation js2 = json:encode([ pretty:true, indent:" " ], [1,2,3]) sput(js2) # => "[ 1, 2, 3 ]" # 3) Partial usage => supply only the 'options' first myEnc = json:encode([ pretty:false ]) res = myEnc( [1,2,3] ) sput(res) # => "[1,2,3]" # 4) Underscore placeholders => skip the first or second param encData = json:encode(_, [ true, false ]) res2 = encData([ pretty:true ]) sput(res2) # => "[ true, false ]"

Usage: `json:encode( optionsKeyedArray, dataValue ) => SingleString(jsonText)`. - The first argument is a KeyedArray (or `_` placeholder) of options. It must at least exist, even if empty: `[ ]`. - The second argument is the Lava data to encode (int, float, array, keyed array, etc.).

Supported options: - `pretty`: bool => if true, uses pretty-printed JSON. - `indent`: SingleString => if `pretty=true`, replaces the default 4-space indentation with a custom string (e.g. "\t" or " ").

If you partially apply, you can pass the options now and the data later, or placeholders for either argument.

Any function or InkTransform encountered in the data is turned into `null` (or bridging default). Mixed numeric arrays unify if possible (int => float, etc.).

exp :math Math JSMath

Returns e^x (the exponential function) for a single numeric argument.
extend("math") sput( math:exp(1) ) # => ~2.718281828 sput( math:exp(0) ) # => 1

One numeric argument only. Returns e^(value).

expect_equal :test Testing Assert

Asserts that the actual value is equal to the expected value, otherwise raises an error that halts the script or test suite.
extend("array") extend("string") describe("example math & array", () => { it("should perform simple addition", () => { expect_equal( 2 + 2, 4 ) }) it("should map numbers in an array", () => { expect_equal( array:map(x => x * 2, [1,2,3]), [2,4,6] ) }) })

If the actual value differs from the expected value, expect_equal throws an error that stops execution of the current test (and possibly the entire script).

This is useful for verifying behavior in small 'it(...)' test blocks.

There is no partial usage for expect_equal—it always takes exactly two arguments: (actual, expected).

expect_error :test Testing Assert

Expects a user function to raise an error when called, optionally checking that the error message contains a given substring.
extend("test") extend("matrix") describe("Checking dimension mismatch via expect_error", () => { it("should raise an error with no substring check", () => { test:expect_error(() => { # Attempt dimension mismatch => matrix:multiply => triggers error matrix:multiply([[1,2,3],[4,5,6]], [[7,8],[9,10]]) }) }) it("should raise an error containing 'dimension mismatch'", () => { test:expect_error( () => { matrix:multiply([[1,2],[3,4,5]], [[7,8],[9,10]]) }, "dimension mismatch" ) }) })

Takes 1 or 2 arguments:

- First argument: a function with no parameters, which we call expecting it to fail.

- Second argument (optional): a string. If present, we check that the error message contains this substring.

If the user function does NOT raise an error, the current test fails immediately. If it raises an error but does not contain the optional substring, the test fails too.

If an error occurs and matches the optional substring (or no substring was provided), the test is considered passed for that scenario.

expect_not_equal :test Testing Assert

Asserts that the actual value is not equal to the expected value, otherwise throws an error that stops the script or test suite.
extend("test") extend("array") extend("string") describe("example math & array", () => { it("should pass given an invalid simple addition", () => { expect_not_equal( 13 + 37, 33 ) }) it("should pass given an invalid result", () => { expect_not_equal( array:map(x => x * 420, [7, 14, 28]), [13, 37] ) }) })

expect_not_equal throws an error if the actual value matches the expected value, causing the current test to fail immediately.

Use this to confirm that two values differ, ensuring your code doesn't produce an unwanted correct match.

expm1 :math Math JSMath

Computes e^x - 1 for a single numeric argument, more accurately for small x than using exp(x)-1.
extend("math") sput( math:expm1(0) ) # => 0 sput( math:expm1(1) ) # => ~1.718281828

Single numeric argument. This is typically more accurate for small x than (exp(x) - 1).

extend :core Core Dynamic

Loads component at runtime by name, then registers its bridging functions into the interpreter.
# Load a component by base name: extend("net") # This searches for a platform-specific library # e.g. libnet.so on Linux, net.dll on Windows, etc. The the functions for that componet can not be calledd. See the rest of documentation for indivual components and usage.

Calling `extend(...)` attempts to load and initialize the specified component’s library. On success, any bridging functions it provides become available in the current interpreter context.

If the library fails to load or does not export a Cargo.lock function, an error is raised immediately.

For details on usage of each loaded component’s functions, consult that component’s individual documentation entries.

fetch :net Network ASYNC

Performs an HTTP GET request to the given URL, then invokes the callback with the response body.
extend("net") # net:fetch usage net:fetch("https://example.com", body => { sput(body) }) # Partial usage is not applicable here. net:fetch expects exactly two arguments: # 1) The URL # 2) A callback function that receives the response body # Example callback that prints the length of the result net:fetch("https://example.org", data => { sput(string:concat("Length is ", string:to_string(array:length(data)))) })

The first argument must be a single string representing the URL.

The second argument must be a function (callback) that takes one argument (the response body as a single string).

net:fetch runs asynchronously, returning immediately with a boolean (true). The actual network request occurs in the background.

When the fetch completes, your callback is called with the raw response body. If the request fails, the callback receives a string describing the error.

file_contents_equal :test Testing Assert

Fails the current test if a file's contents differ from an expected string, or if the file cannot be read.
extend("test") # Basic usage: file_contents_equal("/tmp/myfile.txt", "Hello, world!") # => passes if /tmp/myfile.txt exactly matches "Hello, world!" # If it differs, the test fails with a 'file_contents_equal fail' message. # If the file cannot be read or doesn't exist, the test also fails.

Expects exactly 2 arguments: (filename, expectedString).

If the file contents differ or the file can't be read, it immediately fails the test (e.g., 'file_contents_equal fail').

Part of the 'file_asserts' bridging in the test plugin, primarily used in test code.

file_contents_length_equal :test Testing Assert

Fails the test if the specified file's length in characters is not exactly the given integer, or if the file cannot be read.
extend("test") # Basic usage: file_contents_length_equal("/tmp/report.txt", 100) # => passes if /tmp/report.txt is exactly 100 characters. # If it's a different length or unreadable, the test fails.

Expects exactly 2 arguments: (filename, lengthInt).

Reads the file as text, measures its length in characters. If it doesn't match lengthInt, fails the test with an error message.

If the file cannot be opened, the test also fails.

file_contents_not_equal :test Testing Assert

Fails the current test if a file's contents match the given string, or if the file cannot be read.
extend("test") # Basic usage: file_contents_not_equal("/tmp/output.log", "This should not be present") # => passes if the file content is different. # => fails if it's exactly the same, or if the file can't be read.

Expects exactly 2 arguments: (filename, compareString).

If the file contents match the given string or the file can't be read, the test fails immediately with an error message.

Useful for asserting that a file does NOT contain certain output or contents.

filter :array Array PARTIAL

Returns an array containing only elements that pass a predicate function. Supports partial usage with placeholders.
extend("array") # Direct array:filter( n => n > 10, [4,8,15,16,23,42] ) // IntArray([15, 16, 23, 42]) # Partial myFilter = array:filter(n => n % 2 == 0) myFilter([1,2,3,4,5]) // IntArray([2, 4]) # Plceholder myPartial = array:filter(_, [10,20,3,5]) myPartial(x => x < 10) // IntArray([3, 5])

Accepts 1 or 2 arguments: (predicateFn[, data]).

If called with 1 argument (predicate), it returns a partial function waiting for the data array.

If called with 2 arguments, it immediately filters the array.

The data must be int[], str[], or float[]. For each element, the predicate is called. If it returns true, the element is included in the result. If it returns false, it is excluded.

filter :flow Flow PARTIAL

Creates an InkTransform that only yields items for which your predicate function returns true or a non-zero numeric value.
extend("flow") # 1) Provide a predicate and an InkIterator: filtered = flow:filter(x => x > 10, ink(4,15)) arr = flow:to_array(filtered) sput(arr) # => [11,12,13,14] # 2) Partial usage => define the predicate, wait for the source: predFn = x => x % 2 == 0 myPartial = flow:filter(predFn) res = flow:to_array( myPartial( ink(1,8) ) ) # => [2,4,6] # 3) If used with an InkTransform, it chains, discarding items not passing the filter.

Expects up to 2 arguments => (predicateFn, source). If fewer or placeholders, returns partial usage until both are known.

source can be an InkIterator or an InkTransform. The resulting transform only yields items for which predicate returns a truthy result: bool(true) or a non-zero number.

If the predicate returns bool(false), 0, or an error, that item is skipped or iteration stops. Mixed or invalid predicate results raise an error.

Combine with flow:to_array(...) or another transform for final consumption or chaining.

floor :math Math JSMath

Rounds a single numeric argument down to the nearest integer, returning a float or int.
extend("math") sput( math:floor(3.99) ) # => 3 sput( math:floor(-2.1) ) # => -3

One numeric argument. Returns the greatest integer ≤ x.

fround :math Math JSMath

Rounds a float to 32-bit single precision.
extend("math") sput( math:fround(1.337) ) # => ~1.3370000123977661 sput( math:fround(1e-50) ) # => 0

Single numeric argument. Converts to the closest 32-bit float representation, then returns it as a 64-bit float (depending on bridging).

hadamard :gpu GPU PARTIAL

Elementwise (Hadamard) multiplication of two tensors on the GPU. Both must have the same shape. Partial usage is possible.
extend("gpu") # 1) Basic hadamard => elementwise multiply A = gpu:to_tensor([[1,2],[3,4]]) B = gpu:to_tensor([[10,10],[2,2]]) C = gpu:hadamard(A, B) slog(gpu:to_array(C)) # => [[10.0,20.0],[6.0,8.0]] # 2) Partial usage => known B, missing A hadB = gpu:hadamard(_, B) res = hadB(A) slog(gpu:to_array(res)) # => [[10.0,20.0],[6.0,8.0]] # 3) If shapes mismatch => bridging error. # 4) If GPU path not implemented => logs fallback CPU.

gpu:hadamard => A[i] * B[i] for each element. Both tensors must share the same shape.

If dimension mismatch, bridging raises an error. If GPU is unavailable, CPU fallback occurs.

Partial usage => pass just A or B first. E.g. hadX = gpu:hadamard(A), then hadX(B).

has_key :test Testing Assert

Asserts that a keyed array contains the specified key. If the key is missing or the subject is not keyed, it fails the test.
extend("test") extend("array") describe("Test has_key", () => { it("should confirm a keyed array has a 'foo' key", () => { obj = [ foo:"bar", number:100 ] has_key(obj, "foo") // pass }) it("should fail if the key is missing", () => { obj = [ alpha:42 ] has_key(obj, "beta") // fails test }) it("should fail if the subject is not keyed array", () => { has_key([1,2,3], "index") // fails test }) })

The first argument must be a keyed array, e.g. `[someKey:"value", anotherKey: 123]`.

The second argument must be a single string representing the key name.

If the key is absent, has_key(...) immediately fails the test, appending a 'missing key' message.

If the subject is not a keyed array, it also fails the test with an appropriate error.

hypot :math Math JSMath PARTIAL

Returns the square root of the sum of squares of all given arguments. (Variadic) Partial usage is supported for passing multiple numbers incrementally.
extend("math") # Direct usage: multiple arguments sput( math:hypot(3, 4) ) # => 5 # Variadic usage: sput( math:hypot(3, 4, 12, 84) ) # => sqrt(3^2 + 4^2 + 12^2 + 84^2) # Partial usage => supply some arguments first someHypot = math:hypot(6) # => function waiting for more numbers sput( someHypot(8, 10) ) # => sqrt(36 + 64 + 100) => 13

Any number of numeric arguments. Summation of squares => sqrt(...) is computed and returned as float.

If called with fewer arguments, partial usage accumulates them until all are known, then calculates the final result on call.

imul :math Math JSMath PARTIAL

Performs 32-bit integer multiplication of two arguments, returning a 32-bit int. Partial usage is supported for skipping the first or second argument.
extend("math") # Direct usage sput( math:imul(2, 3) ) # => 6 (strict 32-bit multiply) # Partial usage mul2 = math:imul(2) sput( mul2(1000000000) ) # => wraps in 32-bit if overflow occurs # or underscore placeholder mulX = math:imul(_, 256) sput( mulX(512) ) # => 131072 or possibly wrapped in 32-bit

Takes exactly two arguments, both coerced to 32-bit signed integers, returning the 32-bit product with overflow wrap behavior.

Partial usage: supply just one argument or use `_` to skip the first or second parameter.

info :process Process ASYNC

Retrieves environment and runtime details for the current process, asynchronously calling your callback with a keyed array of data.
extend("process") # Example usage process:info(info => { has_key(info, "pid") has_key(info, "username") # Optionally check that info["platform"] is "linux" or such slog(string:to_string(info)) }) # The callback receives a keyed array with fields like "pid", "uid", # "username", "platform", "binary_name", and so on.

Accepts exactly one argument: a callback function. The callback is invoked asynchronously.

The callback receives a KeyedArray containing process-related details, such as:

- pid: an integer process ID

- uid (on Unix) or 0 on other systems

- username: current user name

- binary_name: name of the current executable

- cwd: current working directory path as a string

- platform & architecture: e.g. "linux" / "x86_64"

The test harness or main loop typically calls process:check_tasks to wait for any tasks spawned by process:info to complete.

ink :array Array Lazy

Creates a lazy iterator producing integer values from start (inclusive) to end (exclusive). Useful for large ranges without storing all elements in memory.
extend("array") # Basic usage => returns an InkIterator from 5 up to (not including) 10 inkIter = array:ink(5, 10) sput( inkIter ) # => <InkIterator handle> (a lazy sequence) # We can convert it to a real array via array:map identity or partial usage: res = array:map(x => x, inkIter) sput(res) # => [5,6,7,8,9] # Or reduce it without building the entire array: sumVal = array:reduce((acc,x)=>acc+x, 0, inkIter) sput(sumVal) # => 35 # If you call array:ink with start >= end => no elements. # In many builds, partial usage is not standard for array:ink, so you must supply both integers.

Usage: array:ink(start, end) => returns an InkIterator that yields each integer from start (inclusive) to end (exclusive).

Unlike array:range, ink does not build the entire array in memory. Instead, it produces values lazily, on demand. This is beneficial for very large ranges or streaming scenarios.

The returned type is InkIterator, which you can pass to array:map, array:reduce, or other bridging functions that support iteration over InkIterator.

Both arguments must be integers. If non-integer values are passed, or if you pass fewer/more arguments, an error is raised.

interval :event Event PARTIAL Async

Schedules a repeating callback that runs every N milliseconds until stopped. Returns a numeric handle used with event:stop.
extend("event") # Basic usage: handle = event:interval(1000, () => { slog("Tick!") }) # => Logs "Tick!" every 1 second. # The function returns an integer handle used to stop it: event:stop(handle) # Partial usage => fix the delay or callback up front. myIntervalFunc = ( ) => { sput("Hello again!") } setupEvery2s = event:interval(2000) # supply the callback now: myHandle = setupEvery2s(myIntervalFunc) # => calls 'myIntervalFunc' every 2s. # To stop it: event:stop(myHandle)
# Placeholder usage: myPartial = event:interval(_, () => { slog("Fires repeatedly.") }) myHandle2 = myPartial(300) # => every 300ms

Arguments: (delayMS, callback).

- `delayMS`: integer or single-element IntArray specifying the repeat interval in milliseconds.

- `callback`: a function with no parameters, called each time the interval elapses.

Returns an integer handle. Pass that handle to `event:stop(handle)` to cancel the interval so it no longer fires.

If you omit or partial-apply an argument, it returns a partial function needing the missing argument(s).

Intervals never stop on their own; you must call `event:stop(handle)` or exit the script.

inverse :gpu GPU

Computes the matrix inverse of a (2×2) tensor on the GPU. In many builds, real GPU code is not implemented yet, so it may fallback to CPU.
extend("gpu") # 1) Invert a 2×2 matrix => shape [2,2] M = gpu:to_tensor([[1,2],[3,4]]) invM = gpu:inverse(M) slog(gpu:to_array(invM)) # => e.g. [[-2.0,1.0],[1.5,-0.5]] # 2) If determinant is near zero => bridging raises an error. # 3) Some builds have no real GPU kernel => logs fallback CPU.

gpu:inverse => only supports 2×2. If shape is not [2,2], bridging raises an error. If the matrix is nearly singular, it errors with 'cannot invert'.

Often used as a minimal demonstration. For bigger NxN, see advanced GPU solvers or third-party libraries.

No partial usage by default; expects exactly 1 argument.

it :test Testing Case

Defines an individual test case with a descriptive name, then calls the provided callback to perform assertions.
extend("test") describe("1+1", () => { it("should be 2", () => { expect_equal( 1 + 1, 2 ) }) })

The first argument is a descriptive string for the test name or scenario.

The second argument is a callback function that typically contains one or more assertions, such as expect_equal(...).

When 'it(...)' is executed, the callback runs immediately. If any assertions fail, it raises an error that halts the test.

keys :array Array

Returns a str-array of all keys in a keyed array. If the input is not keyed, returns an empty array or raises an error (depending on usage).
extend("array") sput( array:keys([ alpha:10, beta:20, gamma:42 ]) ) // => ["alpha", "beta", "gamma"] // If called on a non-keyed array, it typically returns [] or may raise an error in some builds.

Takes exactly one argument, typically a KeyedArray (e.g. [someKey:"value", anotherKey:123]).

Returns a str-array of all the keys in that keyed array, in insertion order.

If you pass a normal int[], str[], or anything else, the result may be an empty array or an error (implementation-dependent).

length :array Array

Returns the length (count of elements or key-value pairs) in an array. Works with int[], str[], bool[], or keyed array.
extend("array") // Regular integer array sput( array:length([10,20,30]) ) // => 3 // Keyed array myKeyed = [ name:"Alice", age:"30" ] sput( array:length(myKeyed) ) // => 2

Accepts exactly one argument which must be an array or keyed array.

Returns an integer: the size of that array or the number of entries in a keyed array.

If the input is not recognized as an array or keyed array, it raises an error.

length :string String

Returns the length of a single string. If not a single string, raises an error.
extend("string") sput( string:length("Hello, Boys!") ) // => 12

Requires exactly one string argument, e.g., "Hello, world!"

Returns an integer value representing the character length of the string.

If you pass something else (like multiple strings or arrays), it raises an error.

line :kanvas Kanvas

Draws a straight line between two points using the given color.
extend("kanvas") win = kanvas:create([ width:400, height:300 ]) kanvas:display(win) kanvas:line(win, [[10,10],[100,80]], "#00FF00")

Arguments:

- Window handle

- Two points: [[x0, y0], [x1, y1]]

- Color string (hex)

Draws a straight line. Use kanvas:refresh to show changes.

list :test TestUtility

Lists available test files by scanning a tests/ directory and returns them as a str-array. Usually called internally by the test runner or used in custom scripts to discover test files.
extend("test") # Basic usage: files = test:list() sput(files) # => e.g. ["arith.mu", "array_test.mu", "io_test.mu"] # It scans your 'tests/' folder (or similar) to gather .mu test scripts.

Takes zero arguments, returns a str-array of test file names (like ["someTest.mu", "otherTest.mu"]).

Primarily for internal use in the 'test' runner bridging but can be called in your scripts to discover test files if desired.

If the 'tests/' directory or .mu files aren’t found, it might return an empty array or raise an error, depending on your environment.

log :math Math JSMath

Returns the natural logarithm (base e) of a single numeric argument > 0.
extend("math") sput( math:log(1) ) # => 0 sput( math:log(10) ) # => ~2.30258509299

Accepts 1 argument > 0. If <= 0, may produce error or NaN (bridge-dependent).

log10 :math Math JSMath

Computes the base-10 logarithm of a single numeric argument > 0.
extend("math") sput( math:log10(1000) ) # => 3 sput( math:log10(1) ) # => 0

One argument, must be positive. Returns log base 10 of value.

log1p :math Math JSMath

Computes ln(1+x) more accurately for small x than log(1+x). One numeric argument > -1.
extend("math") sput( math:log1p(0) ) # => 0 sput( math:log1p(0.1) ) # => ~0.0953101798

Accepts a single numeric argument > -1. This function is typically more precise than log(1+x) for small x.

log2 :math Math JSMath

Returns the base-2 logarithm of a single numeric argument > 0.
extend("math") sput( math:log2(8) ) # => 3 sput( math:log2(1) ) # => 0

One argument > 0, returning log base 2 of that value.

lorem_file :test TestUtility FileIO

Generates a file containing `n` characters of Lorem Ipsum text, returning the file path as a single string.
extend("test") # Basic usage: # test:lorem_file(n) # => Creates a file in ./tmp/lorem_<shortHash>, with n chars of Lorem Ipsum. path = test:lorem_file(200) sput(path) # => prints something like 'tmp/lorem_19ab' or so. # The file is exactly 'n' characters of repeated Lorem text. # Use this for testing file operations (like reading, editing, etc.).

Accepts exactly one argument: an integer specifying how many characters of Lorem Ipsum to write.

Creates a file in your project’s ./tmp subdirectory named 'lorem_<4-hex-hash>'. Returns that path as a single string.

Fails if the file cannot be created or written. Use this for setting up test files of a certain size or content for file-based tests.

lower :array Array

Converts each string in a str-array to lowercase.
extend("array") // Convert all strings in an array to lowercase sput( array:lower(["Hello", "WORLD", "Mu"]) ) // => ["hello", "world", "mu"] // If you pass a single string or a non-string array, an error is raised.

Accepts exactly one argument, which must be a str-array (e.g. ["Hello","WORLD"]).

Returns a new array of strings, each converted to lowercase.

If you pass anything else (a single string, int array, bool array, etc.), it raises an error.

lower :string String

Converts a single string to lowercase.
extend("string") sput( string:lower("Hello, WORLD!") ) // => "hello, world!" # If you pass something other than a single string, it raises an error.

The function takes exactly one string argument and returns its lowercase equivalent.

It will fail if given something that is not a single string (like an array or keyed array).

map :array Array PARTIAL

Applies a function to each element of an array, returning a new array. Supports partial usage for the function or the data array.
extend("array") sput( array:map(n => n * 2, [1,2,3,4]) ) // => [2,4,6,8] # Partial usage myMapper = array:map(n => n + 100) sput( myMapper([5,10,20]) ) // => [105,110,120] # Placeholder => array known, function missing mapArr = array:map(_, [3,9,12]) sput( mapArr(x => x / 3) ) // => [1,3,4]

If called with two arguments (function, array), it applies the function to each element of the array and returns a new array.

If only one argument is supplied, returns a partial function waiting for the other argument (function or data).

The array can be int[], str[], float[] (depending on environment). The function’s return type determines the type of the new array.

max :math Math JSMath PARTIAL

Returns the largest of a set of numeric arguments (variadic). Partial usage allows you to accumulate arguments in steps until you call it.
extend("math") # Direct usage sput( math:max(3, 1, 9, 2) ) # => 9 # Variadic => can pass as many as you like sput( math:max(10, 50, 40, 999, 1002) ) # => 1002 # Partial usage => supply some args first halfMax = math:max(100, 250) # => function waiting for more numbers sput( halfMax(60, 999, 1) ) # => 999

If no arguments are eventually provided, result may be -Infinity or an error, depending on bridging.

If any argument is non-numeric, an error may occur or result is NaN. Implementation detail depends on bridging.

min :math Math JSMath PARTIAL

Returns the smallest of a set of numeric arguments (variadic). Partial usage accumulates arguments until final call.
extend("math") sput( math:min(5, 2, 10, 0) ) # => 0 # Variadic sput( math:min(100, 50, -20, 999) ) # => -20 # Partial usage partMin = math:min(30) sput( partMin(50, 2, 40) ) # => 2

Any number of numeric arguments. If bridging sees no final arguments, the result might be +Infinity or an error.

Partial usage: supply arguments in stages until final invocation.

multiply :gpu GPU Matrix PARTIAL

Performs a standard 2D matrix multiplication (A×B) on the GPU, returning a new 2D tensor. Supports partial usage and shape mismatch checks.
extend("gpu") # 1) Basic matrix multiply => 2×2 by 2×2 A = gpu:to_tensor([[1,2],[3,4]]) B = gpu:to_tensor([[5,6],[7,8]]) C = gpu:multiply(A, B) slog(gpu:to_array(C)) # => Float2DArray([[19.0, 22.0],[43.0, 50.0]]) # 2) Partial usage => known A, missing B mulA = gpu:multiply(A) res = mulA(B) slog(gpu:to_array(res)) # => [[19.0, 22.0],[43.0, 50.0]] # 3) Shape mismatch => error # Attempt 2×3 multiplied by 2×2 => dimension mismatch => triggers fallback CPU or error # test:expect_error(() => { # gpu:multiply( gpu:to_tensor([[1,2,3],[4,5,6]]), gpu:to_tensor([[7,8],[9,10]]) ) # }, # "Dimension mismatch" # ) # 4) CPU fallback => if no real GPU pipeline is found, or if bridging is incomplete, # the code logs "fallback CPU" but still calculates the result with a CPU approach.

gpu:multiply(A,B) multiplies two 2D tensors A (m×k) and B (k×n). The result is (m×n).

If shapes mismatch, bridging raises an error. If GPU is unavailable or not implemented for multiply, it may fallback to CPU with a console message.

Partial usage: you can call gpu:multiply(A) => returns a function expecting B, or placeholders (gpu:multiply(_, B)) => expects A next.

multiply :math Math PARTIAL

Multiplies one number (or array of numbers) by another, supporting partial usage and underscore placeholders.
extend("math") # Direct usage sput( math:multiply(6, 7) ) # => 42 # Partial usage => provide only the first argument mul10 = math:multiply(10) sput( mul10(5) ) # => 50 # Underscore placeholder => skip the first argument mul3 = math:multiply(_, 3) sput( mul3(11) ) # => 33 # If either argument is an array, it performs element-wise multiplication sput( math:multiply(5, [2,4,6]) ) # => [10, 20, 30] sput( math:multiply([3,3,3], 2) ) # => [6, 6, 6]

If both arguments are single integers, it returns their product.

If one argument is an integer array, it returns an integer array of element-wise products.

You can partially apply `multiply` by providing only one argument, returning a function waiting for the other argument.

Use the underscore placeholder `_` if you need to skip the first parameter while providing the second (or vice versa).

multiply :matrix Matrix PARTIAL

Performs standard matrix multiplication of two 2D arrays (int2d or float2d).
extend("matrix") # 1) Standard usage => multiply 2×2 by 2×2 A = [[1,2],[3,4]] B = [[5,6],[7,8]] product = matrix:multiply(A,B) # => [[19,22],[43,50]] sput(product) # 2) Partial usage => known A, missing B mulA = matrix:multiply(A) res = mulA(B) sput(res) # => [[19,22],[43,50]] # 3) Dimension mismatch => raises an error. # test:expect_error( # () => { matrix:multiply([[1,2,3],[4,5,6]], [[7,8],[9,10]]) }, # "dimension mismatch" # ) # 4) Float usage => multiply float2d arrays F1 = [[1.1,2.1],[3.5,4.5]] F2 = [[5.2,6.2],[7.1,8.9]] floatProd = matrix:multiply(F1,F2) # => [[20.630000000000003, 25.51],[50.15, 61.75]] sput(floatProd)

Takes (A, B). If shapes are compatible => result is M×P if A is M×N and B is N×P.

If dimension mismatch (A’s columns != B’s rows), it raises an error. If one arg is missing, partial usage awaits the second array.

Supports both int2d_array and float2d_array. If mixing, you might get a float2d_array result.

nth :array Array PARTIAL

Retrieves the nth element of an array, supporting negative indices (counting from the end). Returns '_' if out of range. Partial usage is supported.
extend("array") // Basic usage sput( array:nth(0, ["A","B","C"]) ) // => "A" sput( array:nth(-1, ["A","B","C"]) ) // => "C" // If out of range => returns '_' // Partial usage getThird = array:nth(2) sput( getThird([10,20,30,40]) ) // => 30 myPartial = array:nth(_, [5,6,7,8]) sput( myPartial(-2) ) // => 7

The first argument is an integer index. Negative indices count from the end, e.g. -1 => last element.

The second argument is the array. Must be int[], str[], or bool[].

If the index is out of range, returns '_'. If any argument is missing, you get a partial function requiring the missing parameter.

ping :net Network ASYNC

Initiates an asynchronous ping to a given host or IP
extend("net") net:ping([ dest: "cube.nu11.uk", count: 5 ], sput) localhost_ping = net:ping("127.0.0.1", sput) net:ping([ dest: "cube.nu11.uk", count: 5 ], sput) eight_ping = net:ping([ dest: "8.8.8.8" ], sput) nine_ping = net:ping([ dest: "9.9.9.9", interval: 100, count: 20 ], sput) net:stop(localhost_ping)

The first argument can be a single string (e.g., "127.0.0.1") or a keyed array with fields like dest, count, or interval.

The second argument must be a callback function that processes each ping reply.

Returns an integer task ID. Use net:stop(taskId) to cancel an ongoing ping.

If run with proper privileges on Unix, raw ICMP is used; otherwise, the system ping command is used.

You can specify a count to limit the number of pings and an interval (in milliseconds) to adjust the delay between pings.

pipe :core Core PARTIAL

Combines multiple functions left-to-right, returning a single function. The output of one function flows to the next.
############################################ # Example usage of pipe(...) ############################################ # 1) Suppose we have some functions: # string:upper => converts a single string to uppercase # string:length => returns the length of a single string # plus(10) => adds 10 to a number extend("string") extend("array") # 2) We create a pipeline using pipe: # The data flows from left to right. # So we first call string:upper on the input, # then string:length, # then plus(10), # then sput receives the final result. myPipeline = pipe( string:upper, string:length, plus(10), sput ) # 3) Now calling myPipeline("hello") executes in left-to-right order: # - string:upper("hello") => "HELLO" # - string:length("HELLO") => 5 # - plus(10)(5) => 15 # - sput(15) => prints 15 myPipeline("hello") # => prints 15

pipe(...) works similarly to compose, but the functions are executed from left to right: pipe(f, g, h)(x) => h(g(f(x))).

If you prefer right-to-left ordering, see compose(...).

You can partially apply pipe by providing fewer function arguments. Missing spots can use underscore placeholders. Once all functions are known, you get a single function to call with your data.

pixel :kanvas Kanvas

Sets a single pixel to the specified color in the window.
extend("kanvas") win = kanvas:create([ width:320, height:200 ]) kanvas:display(win) kanvas:pixel(win, [10,15], "#FF00FF") # sets pixel at (10,15) to magenta

Arguments:

- Window handle

- Coordinates as an [x, y] array (integers)

- Color as a string (e.g. '#RRGGBB' or '#AARRGGBB')

Colors support hex formats. Coordinates are zero-based. No return value.

Call kanvas:refresh(win) to display updates.

plus :math Arithmetic PARTIAL

Adds an integer (or array of integers) to another integer or array. Supports partial usage and underscore placeholders.
extend("math") # Straight usage sput( math:plus(3, 4) ) // => 7 # Partial usage plusTen = math:plus(10) sput( plusTen(5) ) // => 15 # Placeholder usage => skip the first parameter plusTwo = math:plus(_, 2) sput( plusTwo(10) ) // => 12 # Arrays => second argument can be [10,20,30] sput( math:plus(5, [10,20,30]) ) // => [15,25,35]

When both arguments are single integers, the result is a single integer (e.g. 3 + 4 = 7).

If one argument is an integer array, the result is an integer array of element-wise sums (e.g. plus(5, [10,20,30]) -> [15,25,35]).

You can partially apply `plus` by supplying only one argument. For example, `plus(10)` returns a new function expecting the second argument.

Use the underscore placeholder (`_`) if you need to omit the first parameter instead of the second (e.g. `plus(_, 2)`).

pow :math Math PARTIAL

Raises a base to an exponent. Supports partial usage, placeholders, and negative exponents are disallowed by default.
extend("math") # Normal usage sput( math:pow(2, 3) ) // prints 8 # Partial usage => supply just the base square = math:pow(2) sput( square(5) ) // prints 32 (2^5 = 32) # Placeholder usage => skip the base, fix exponent=3 raise3 = math:pow(_, 3) sput( raise3(2) ) // prints 8

If called with two integers, pow(base, exponent) returns base^exponent, failing on negative exponents.

If only one argument is given, returns a partial function that expects the missing argument.

Placeholders allow skipping the first parameter instead of the last.

Because it is registered as 'math:pow', you must call it as math:pow(...) unless you rebind it.

prop :array Array PARTIAL

Retrieves the value of a specified key from a keyed array. Supports partial usage and placeholders for the key or the object (or both).
extend("array") keyedExample = [ name:"Alice", city:"Paris" ] sput( array:prop("name", keyedExample) ) // => "Alice" # Partial usage => known key, missing object getCity = array:prop("city") sput( getCity(keyedExample) ) // => "Paris" # Placeholder => known object, missing key getSomething = array:prop(_, keyedExample) sput( getSomething("name") ) // => "Alice"

If both a key (string) and a keyed array are provided, the value for that key is returned immediately.

If only one of them is provided, returns a partial function that expects the missing argument.

Raises an error if the object is not a keyed array or if the key is not a valid single string.

prop_equals :test Testing Assert

Asserts that the specified key in a keyed array has the expected value. If missing or different, it fails the test immediately.
extend("test") extend("array") describe("Test prop_equals", () => { it("should confirm the 'city' key is 'London'", () => { obj = [ name:"Alice", city:"London" ] prop_equals(obj, "city", "London") // pass }) it("fails if the actual key's value doesn't match expected", () => { obj = [ city:"Paris" ] prop_equals(obj, "city", "London") // fails test }) it("fails if the key doesn't exist or the subject isn't keyed", () => { prop_equals([ a:1 ], "b", 99) // missing key => fail prop_equals([10,20,30], "0", 10) // not keyed => fail }) })

The first argument must be a keyed array, e.g. `[ city:"London" ]`.

The second argument is a single string (key name). If that key is missing, the test fails.

The third argument is the expected value. If the actual value differs, the test fails with a 'mismatch' message.

Use prop_equals(...) for quick checks of a keyed array's property.

range :array Array PARTIAL

Produces an IntArray of consecutive integers from start (inclusive) up to end (exclusive). Partial usage is supported for start/end arguments.
extend("array") // array:range(0, 5) => [0,1,2,3,4] sput( array:range(0, 5) ) // => [0,1,2,3,4] // If start >= end => returns an empty array // Partial usage => only provide start rangeFrom2 = array:range(2) sput( rangeFrom2(6) ) // => [2,3,4,5] // Placeholders => array:range(_, 5), etc.

Accepts two integer arguments: start, end. Generates an array of integers [start..end).

If only one is provided, it returns a partial function expecting the other. If both are missing or `_`, partial usage continues until both are known.

Negative or reversed ranges result in an empty array. This is akin to many functional libraries’ range semantics.

read :file FileIO PARTIAL

Reads the contents of a file from disk. If given one argument, returns all contents as a single string. If a second callback argument is provided, streams the file in chunks.
# 1) Basic usage (one argument): read an entire file at once. extend("file") contents = file:read("/path/to/myfile.txt") sput(contents) # => Prints all text from that file as a single string. # If the file doesn't exist or is unreadable, raises an error.
# 2) Streaming usage (two arguments: path, chunkCallback) file:read("/path/to/largefile.bin", chunk => { # chunk is a string (or binary data) for the next part of the file. # This callback is invoked repeatedly until EOF. # Example: Collect chunk lengths slog(string:concat("Received chunk of ", string:to_string(string:length(chunk)), " bytes")) }) # => The function returns immediately with a boolean (true) or a handle. # Meanwhile, the callback is called for each chunk read. # If you need partial usage, see the placeholders below.
# 3) Partial usage => placeholders # You can supply just the path, leaving a placeholder for the callback: myPartialRead = file:read("/path/data.log", _) # Then call that function with the chunk callback: myPartialRead(chunk => { # handle chunk here }) # Or supply the callback first, leaving the path as a placeholder.

Argument patterns: - If called with 1 argument (path:string), the entire file is read at once and returned as a single string. - If called with 2 arguments (path:string, chunkCallback:function), the function processes the file in streaming mode. It returns immediately (e.g. true), then repeatedly calls your callback with each chunk of data until EOF.

In streaming mode, the callback takes exactly one argument: the chunk (as a string or bytes). If an error occurs, file:read typically raises an exception or passes an error string to the callback (implementation‐dependent).

You can use partial usage. For example, `file:read(path, _)` returns a function that waits for the callback. Or `_` for the path, if you want to fix the callback first.

If your environment does not support streaming, these second-argument references may be ignored or raise an error.

rectangle :kanvas Kanvas

Draws a filled rectangle between two corner points.
extend("kanvas") win = kanvas:create([ width:400, height:300 ]) kanvas:display(win) kanvas:rectangle(win, [[10,15],[100,60]], "#FF0000") # draws red rectangle

Arguments:

- Window handle

- Two-element array: [[x0, y0], [x1, y1]] (top-left and bottom-right corners)

- Color string (e.g. '#FF0000' for red)

Draws a filled rectangle. Coordinates must be within window bounds.

reduce :array Array PARTIAL

Folds (reduces) an array with a user-supplied function and initial value. Supports partial usage and underscore placeholders.
extend("array") extend("string") # Example sput( array:reduce((acc, value) => acc + value, 0, [4,8,15,16,23,42]) ) // => 108 # Partial usage sumFn = (acc, x) => acc + x sumReducer = array:reduce(sumFn, 0) sput( sumReducer([1,2,3]) ) // => 6

Expects up to three arguments: (function, initialValue, data). Missing arguments become placeholders or partial usage.

The user-supplied function is invoked for each element. Typically, the reduce-lambda uses a curried approach: first call with (acc), then call with (item).

Raises an error if the data is not an int[], str[], or recognized array type.

reduce_sum :gpu GPU

Sums all elements of a 2D float32 tensor on the GPU, returning a single numeric Value. If GPU is not implemented, logs fallback CPU.
extend("gpu") X = gpu:to_tensor([[1,2,3],[4,5,6]]) val = gpu:reduce_sum(X) slog(val) # => 21.0 (1+2+3+4+5+6) # If bridging doesn't have a real GPU kernel, logs fallback CPU path. # Use case => summing entire matrix for debugging, cost calculation, or normalizing data.

gpu:reduce_sum => expects exactly one 2D float32 tensor. Returns a single float result (like 21.0).

If bridging is incomplete, logs fallback CPU. For large shapes, a real GPU kernel can speed up summation significantly, if available.

No partial usage is typically provided for reduce_sum; it requires exactly 1 argument.

refresh :kanvas Kanvas

Refreshes (repaints) the Kanvas window, displaying any changes made by draw functions since the last refresh.
extend("kanvas") win = kanvas:create([ width: 320, height: 240, title: "Demo" ]) kanvas:display(win) # Draw shapes, lines, pixels, etc. kanvas:rectangle(win, [[20,30],[100,60]], "#00FF00") # Draw green rectangle kanvas:pixel(win, [50, 50], "#FF0000") # Draw red pixel kanvas:triangle(win, [[10,10],[200,50],[50,100]], "#FF00FF") # Now update the window so all drawings appear kanvas:refresh(win)

Arguments:

- Window handle (returned by kanvas:create).

Call kanvas:refresh after one or more drawing operations (like kanvas:pixel, kanvas:rectangle, etc.) to display changes on the screen.

If you do not call refresh, the window may not visibly update, depending on platform or bridging implementation.

Does not return a value.

rotate_point :math Math Geometry

Rotates a 2D point (x, y) by a specified angle in radians, returning the new coordinates as a float array.
extend("math") # Rotate point (1, 0) by 90 degrees (π/2 radians): res = math:rotate_point(1, 0, 3.14159265359 / 2) sput(res) # => [0.0, 1.0] # Rotate (0, 1) by -90 degrees (-π/2 radians): res = math:rotate_point(0, 1, -3.14159265359 / 2) sput(res) # => [1.0, 0.0] # Usage: math:rotate_point(x, y, angleRad) # Returns: [rotatedX, rotatedY]

Arguments: (x, y, rad)

- x: X coordinate (int or float)

- y: Y coordinate (int or float)

- rad: Angle in radians (float/int). Positive is counterclockwise.

Returns: FloatArray [rotatedX, rotatedY].

Example: Rotating (1,0) by π/2 radians yields (0,1).

Raises an error if arguments are missing or not numeric.

round :math Math JSMath

Rounds a single numeric argument to the nearest integer (ties typically go to +∞ or to even, bridging-dependent).
extend("math") sput( math:round(3.5) ) # => 4 or bridging depends (some may do bank rounding) sput( math:round(-1.2) ) # => -1

One numeric argument. Behavior for .5 depends on your environment's bridging (it might round half up or to even).

run :test TestUtility ASYNC

Runs a single test file and calls a callback with a mesag
extend("test") file = "arith.mu" test:run(file, slog)

Accepts exactly 2 arguments: (filename, callback).

filename is a test file in the tests/ folder

scale :gpu GPU PARTIAL

Multiplies every element of a 2D tensor by a scalar (int/float) on the GPU, returning a new tensor of the same shape. Partial usage is allowed.
extend("gpu") # 1) Basic usage => scalar * matrix Mat = gpu:to_tensor([[1,2,3,4],[5,6,7,8]]) Scaled = gpu:scale(10, Mat) slog(gpu:to_array(Scaled)) # => [[10.0,20.0,30.0,40.0],[50.0,60.0,70.0,80.0]] # 2) Partial usage => known scalar, missing matrix scaleBy0_5 = gpu:scale(0.5) res = scaleBy0_5(Mat) slog(gpu:to_array(res)) # => [[0.5,1.0,1.5,2.0],[2.5,3.0,3.5,4.0]] # 3) If bridging lacks real GPU logic => logs fallback CPU, but result is the same.

Takes exactly 2 arguments => (scalar, tensor). The scalar can be int or float. The second must be a 2D float32 tensor.

gpu:scale => elementwise multiplication by the scalar. Returns a new tensor with identical shape.

If GPU is missing or not implemented for scale, logs fallback CPU. Partial usage => e.g. scale(10) => a function expecting the matrix next.

sign :math Math JSMath

Returns the sign of a number
extend("math") sput( math:sign(10) ) # => 1 sput( math:sign(-5) ) # => -1 sput( math:sign(0) ) # => 0

-1 if negative, +1 if positive, 0 if zero

sin :math Math JSMath

Returns the sine of a single numeric argument in radians
extend("math") sput( math:sin(0) ) # => 0 sput( math:sin(3.14159/2) ) # => ~1

One argument in radians. Returns float sin(x).

sinh :math Math JSMath

The hyperbolic sine of a single numeric argument.
extend("math") sput( math:sinh(0) ) # => 0 sput( math:sinh(1) ) # => ~1.175201193

One numeric argument => returns float for sinh(x). hyperbolic functions are similar to standard trigonometric functions but instead use a hyperbolic curve not a circle as a reference.

slice :flow Flow PARTIAL

Returns an InkTransform that skips a certain number of items and then yields a limited count of items from an InkIterator or InkTransform.
extend("flow") # Example => skip=1, count=4 from an ink(1..50) partialChain = flow:compose( flow:to_array, flow:slice(1,4), flow:trans(n => n * 10) ) # So the data => ink(1,50) => [1,2,3,4,5,...] # => trans(n => n*10) => [10,20,30,40,50,...] # => slice(1,4) => skip the first => yield next 4 => [20,30,40,50] # => flow:to_array => finalize => int_array result = partialChain( ink(1,50) ) sput(result) # => [20,30,40,50] # Partial usage => placeholders, or only skip & count known, waiting for the source.

Accepts up to three arguments => (skip, count, source). If some are placeholders, returns partial usage. If all are resolved, yields an InkTransform that reads from the given source (an InkIterator or InkTransform).

skip is how many items to discard first, count is how many items to produce next, ignoring the rest. Once count items are produced, iteration returns 'NO_MORE_DATA'.

If skip or count is negative, it’s treated as 0 in some bridging logic, or yields an error in others, depending on your environment.

slog :core Core Print

Prints a value with a 'LOG:' prefix, then returns the value unchanged.
############################################ # Example usage: ############################################ # Provide any single argument to slog. slog(123) # prints 'LOG: 123', returns 123 myStr = "Hello" slog(myStr) # prints 'LOG: Hello', returns 'Hello' # No partial usage is supported. If called with no # or multiple arguments, an error is raised.

Like `sput`, requires exactly one argument of any Value type.

Prepends 'LOG: ' to the printed output, then returns the argument unchanged.

Useful for verbose logging, leaving behind 'LOG:' markers in your console output.

sput :core Core Print

Prints a value in bracketed form, then returns that same value unchanged.
############################################ # Example usage: ############################################ # 1) Provide any single argument to sput. sput(123) # prints '123', returns 123 nums = [1,2,3] sput(nums) # prints '[1, 2, 3]', returns the original [1,2,3] # 2) The function does not support partial usage or placeholders. # 3) If multiple arguments are provided, an error is raised.

Requires exactly one argument (of any Value type).

Prints a bracketed or typed representation of that argument to stdout, then returns it unchanged.

Use `sput` for debugging or quick prints. If your environment logs to console, you’ll see the output immediately.

sqrt :math Math

Returns the square root of a single non-negative numeric argument. Raises an error if negative.
extend("math") # 1) Direct usage => single argument sput( math:sqrt(25) ) # => 5.0 sput( math:sqrt(3.14) ) # => ~1.77200451466 # 2) Negative inputs typically raise an error or return NaN (depending on bridging): # math:sqrt(-1) => error or invalid. # 3) If bridging does not support partial usage for sqrt, it requires exactly one argument.

Takes exactly one numeric argument >= 0. If negative, bridging may raise an error or produce NaN (implementation-dependent).

Returns a float. If the input was an integer, you still get a float result (e.g., 25 => 5.0).

Does not support partial usage in most builds; if you pass fewer or more than one argument, it raises an error.

srand :math Random Seed

Creates a seeded pseudo-random number generator function from the given integer seed
extend("math") gen = math:srand(42) sput( gen() ) // => e.g. 1608638478 sput( gen() ) // => next number from seed=42

Pass an integer seed to srand, which returns a new generator function.

Each call to the generator produces a next pseudo-random integer based on that seed.

The sequence is deterministic, so the same seed yields the same sequence every time.

stop :event Event Async

Stops a previously scheduled repeating interval by its numeric handle. If no matching interval is found, it quietly does nothing.
extend("event") # Typical usage => first schedule an interval: handle = event:interval(1000, () => { sput("Tick.") }) # Then, to stop it: event:stop(handle) # => The repeating calls end. # If you call event:stop(...) with a handle that doesn't exist or was already canceled, it does nothing.

Takes exactly one argument: the integer handle returned by event:interval(...).

Marks that interval as canceled. On the next poll cycle, it is removed from the event loop.

If the handle does not match any active intervals, nothing happens (no error).

Partial usage is generally not used for event:stop; it expects a single handle argument.

stop :net Network ASYNC

Stops a previously created asynchronous ping by task ID.
extend("net") # Usage with net:ping => returns a task ID pingId = net:ping("127.0.0.1", sput) # Then, to stop that ping net:stop(pingId) # net:stop expects exactly one argument (the token_id returned by net:ping).

After calling net:ping(...), you get back an integer task ID. Pass that same ID to net:stop to cancel the ongoing ping.

If no ping with that ID is found, net:stop does nothing (silently).

This function only affects tasks launched by net:ping in the net plugin.

subtract :gpu GPU PARTIAL

Elementwise subtraction of two tensors on the GPU (A - B). Returns a new tensor with the same shape, or errors on mismatch.
extend("gpu") # 1) Provide two equally sized 2D tensors: A = gpu:to_tensor([[10,12],[3,8]]) B = gpu:to_tensor([[1,2],[3,4]]) C = gpu:subtract(A, B) slog(gpu:to_array(C)) # => [[9.0,10.0],[0.0,4.0]] # 2) Partial usage => known A, missing B subA = gpu:subtract(A) res = subA(B) slog(gpu:to_array(res)) # => [[9.0,10.0],[0.0,4.0]] # 3) If shapes differ, bridging raises an error or logs fallback. # 4) CPU fallback => if GPU not available.

gpu:subtract(A, B) => A[i][j] - B[i][j], shapes must match exactly.

Partial usage => pass one argument now, the second later. E.g. gpu:subtract(A) => function expecting B.

If bridging is incomplete or GPU is unavailable, logs fallback CPU path but still returns the correct result.

subtract :math PARTIAL

Subtracts one number (or array) from another.
extend("math") # Direct sput( math:subtract(10, 3) ) // 7 # Partial sub5 = math:subtract(5) sput( sub5(2) ) // 2 sput( sub5(9) ) // -4 # Placeholder minus20 = math:subtract(_, 20) sput( minus20(50) ) // 30 sput( minus20(5) ) // -15

math:subtract(a, b) returns a - b. If called with only one argument, it returns a partial function waiting for the second number.

Using '_' lets you skip the first parameter, while providing the second immediately. Then the returned partial function expects just the first parameter.

If an array is used for either argument, each element of that array is subtracted by the single integer from the other argument (if supported by your bridging logic).

subtract :matrix Matrix PARTIAL

Performs elementwise subtraction of two 2D arrays. If you only supply one argument, partial usage is applied.
extend("matrix") # 1) Basic usage A = [[1,2],[3,4]] B = [[5,6],[7,8]] res = matrix:subtract(A,B) # => [[-4,-4],[-4,-4]] sput(res) # 2) Partial usage => fix the first argument subFromA = matrix:subtract(A) resultB = subFromA(B) # => [[-4,-4],[-4,-4]] # 3) Placeholder => known second array B, missing A partialSub = matrix:subtract(_, B) out = partialSub(A) # => [[-4,-4],[-4,-4]] # 4) Raises an error if shapes differ or if either argument is not int2d_array or float2d_array.

Takes two arguments (A, B). If only one is provided, returns a function needing the missing array.

Subtracts elementwise => (A[i][j] - B[i][j]). If shape mismatch, an error is raised.

Supports int2d_array and float2d_array. If mixing int2d + float2d, upcast to float2d occurs (depending on bridging).

tail :array Array

Returns a copy of the array without the first element. If the array has 0 or 1 elements, the result is empty.
extend("array") sput( array:tail([1,2,3]) ) // => [2,3] sput( array:tail([]) ) // => [] // If you pass a non-array or a single string, it raises an error.

Accepts exactly one argument: an int[], str[], or bool[].

Returns a new array missing the first element. If the array is empty or length=1, it returns an empty array.

Does not currently support partial usage. Passing multiple arguments triggers an error.

tan :math Math JSMath

Returns the tangent (in radians) of a single numeric argument.
extend("math") sput( math:tan(0) ) # => 0 sput( math:tan(3.14159/4) ) # => ~1 # If near π/2 + kπ, may produce large or Infinity.

Accepts exactly 1 numeric argument in radians. If out of normal range, bridging might produce Infinity or error.

tanh :math Math JSMath

Computes the hyperbolic tangent of a single numeric argument.
extend("math") sput( math:tanh(0) ) # => 0 sput( math:tanh(2) ) # => ~0.96402758

One numeric argument => returns float tanh(x).

throttle :flow Flow PARTIAL

Produces an InkTransform that delays each item by a specified number of milliseconds, controlling the pace of iteration from an InkIterator or InkTransform.
extend("flow") # 1) Basic usage => throttle(100) with an InkIterator iter = ink(1,6) # yields [1,2,3,4,5] throttled = flow:throttle(100, iter) # Convert to array => you'll see a ~100ms delay between each item behind the scenes. arr = flow:to_array(throttled) sput(arr) # => [1,2,3,4,5] # 2) Partial usage => specify ms but wait for the source: th100 = flow:throttle(100) xform = flow:trans(x => x*10, ink(0,3)) res = flow:to_array( th100(xform) ) sput(res) # => [0,10,20], each item delayed 100ms # 3) Combining with existing transforms or partial usage => no difference, just returns a new InkTransform that sleeps between items.

Takes (ms, source). If ms or source is missing or placeholder, partial usage is returned. If both are known, returns an InkTransform that sleeps ms milliseconds between yields.

source can be an InkIterator or another InkTransform. Once you pull items (e.g. with flow:to_array), each retrieval is delayed by ms.

If ms < 0, bridging might raise an error. If the source ends, the transform yields NO_MORE_DATA normally.

timeout :event Event PARTIAL Async

Schedules a single-shot callback to run after a specified delay (in milliseconds). Supports partial usage with placeholders.
extend("event") # Basic usage: # event:timeout(delayMS, callback) # Wait 1 second, then call slog(...) once. event:timeout(1000, () => { slog("One second elapsed!") }) # The callback is invoked exactly once. # Partial usage => fix the delay or callback ahead of time. set5s = event:timeout(5000) set5s(() => { sput("5 seconds passed!") }) # Placeholder => known callback, missing delay: myTimer = event:timeout(_, () => { sput("Delay done.") }) myTimer(2000) # => Waits 2 seconds, then calls sput(...)

Arguments: (delayMS, callback).

- `delayMS`: an integer (or single-element IntArray) specifying how many milliseconds to wait.

- `callback`: a function with no parameters, called once after the delay elapses.

Returns `Bool(true)` or a success indicator if it schedules successfully. The task is automatically removed once it fires.

Partial usage: If you only supply one argument, you get a partial function needing the missing argument. Use `_` placeholders to skip the first parameter if desired.

This function is asynchronous; the script continues running while the timer counts down.

timestamp_micro :sys System

Returns the current epoch time in microseconds (as a 64-bit integer).
############################################################ # Example usage: ############################################################ # 1) Call sys:timestamp_micro() with no arguments. us = sys:timestamp_micro() # 2) Print or store the integer result. sput(us) # This returns the current Unix timestamp in microseconds as a 64-bit integer. # For example, 1,684,413,825,123,456 means ~1.684 trillion microseconds.

sys:timestamp_micro() calls the system clock and returns a 64-bit integer (i64) measuring microseconds since the Unix epoch (1970-01-01).

No arguments are taken; if any arguments are passed, it raises an error.

If you need millisecond precision, see sys:timestamp_ms(). For microseconds, use this function.

timestamp_ms :sys System

Returns the current epoch time in milliseconds (as a 64-bit integer).
############################################ # Example usage: ############################################ # 1) Call sys:timestamp_ms with no arguments. ms = sys:timestamp_ms() # 2) Print or store the integer result. sput(ms) # The returned value is a 64-bit integer measuring # milliseconds since 1970-01-01.

sys:timestamp_ms() makes a synchronous call into the system clock and returns a 64-bit integer representing milliseconds since the Unix epoch (1970-01-01).

No arguments are taken; if you pass any arguments, it raises an error.

If you need finer granularity in microseconds, see sys:timestamp_micro().

to_array :flow Flow

Consumes an InkIterator or InkTransform to produce a final in-memory array of items. Fails if the items are of mixed or unsupported types.
extend("flow") # 1) Direct usage with an InkIterator nums = flow:to_array( ink(1,5) ) sput(nums) # => [1,2,3,4] # 2) With an InkTransform => e.g. flow:trans xf = flow:trans(x => x*2, ink(2,5)) arr = flow:to_array(xf) sput(arr) # => [4,6,8] # 3) If the iteration yields a mix of ints, floats, or strings, bridging may raise an error or handle partial upcasting. Usually all items must unify to a single array type.

Takes exactly one argument => (source). The source must be an InkIterator or an InkTransform.

It repeatedly retrieves items until 'NO_MORE_DATA', gathering them into an int_array, float_array, or str_array if uniform. Mixed types cause an error unless your bridging code supports a generic array.

This is a final stage that pulls the entire stream into memory. For extremely large streams, consider using partial consumption or separate techniques if memory is a concern.

to_array :gpu GPU

Converts a rank=2 float32 TensorValue back into a float2D_array in Mu’s script environment. Errors if shape is not 2D.
extend("gpu") # 1) Suppose T is shape [3×2] myTensor = gpu:to_tensor([[1,2],[3,4],[5,6]]) arr = gpu:to_array(myTensor) slog(arr) # => Float2DArray([[1.0,2.0],[3.0,4.0],[5.0,6.0]]) # 2) If the input is not rank=2 or not float32, bridging logs an error. # 3) This is typically the final step after a GPU operation, retrieving results for printing or further script logic.

Requires exactly 1 argument: a Value::Tensor with elem_type=Float32 and shape=[rows, cols].

Returns a float2D_array by reading each row from the data buffer.

If bridging sees shape != 2D, or the data is not float32, an error is raised. This function is a standard finishing step after GPU-based transforms.

to_string :string String

Converts any value value into a single string
extend("string") sput( string:to_string(123) ) // => "123" sput( string:to_string([1,2,3]) ) // => "[1, 2, 3]" myKeyed = [ name:"Bob", age:42, isCool:true ] sput( string:to_string(myKeyed) ) // => "{ name: Function(...) age: ... }" // (The exact representation for KeyedArray may differ based on your debug printing logic.) sput( string:to_string("Hello, world!") ) // => "Hello, world!"

Takes one argument (of any Value type) and returns a single string representation.

If the Value is already a string, it simply returns that string.

Use string:to_string in places where you need a textual representation of any data. or if a string is require by a function such as string:concat

to_tensor :gpu GPU

Converts an int2D_array or float2D_array into a GPU-ready float32 tensor (rank=2). Logs an error if shape is inconsistent or data is empty.
extend("gpu") # 1) Convert 2D int array => rank=2 float32 tensor arrI = [[1,2],[3,4],[5,6]] T = gpu:to_tensor(arrI) slog(T) # => TensorValue(...) with shape=[3,2], elem_type=Float32 # 2) Convert 2D float array => same concept arrF = [[1.1,2.2],[3.3,4.4]] TF = gpu:to_tensor(arrF) slog(TF) # => shape=[2,2], data as float32 # If bridging sees an empty array or ragged rows, it raises an error.

gpu:to_tensor => exactly 1 argument: a 2D array (either int2D_array or float2D_array). The resulting shape is [rows, cols].

All values become float32. If rows differ in length, bridging fails with an 'inconsistent row lengths' error.

Used as the first step for GPU ops like multiply, add, etc.

trans :flow Flow PARTIAL

Applies a user-defined function to each item from an InkIterator or InkTransform, returning a new InkTransform that yields transformed items one at a time.
extend("flow") # 1) Use an InkIterator as input: transform = flow:trans(x => x+1, ink(1,5)) # => an InkTransform that yields each integer from [1..5), adding 1 => [2..6). # 2) Retrieve the items => flow:to_array result = flow:to_array(transform) sput(result) # => [2,3,4,5,6] # 3) Chain multiple transforms: stepA = flow:trans(x => x * 2) stepB = flow:trans(x => x + 100) # Compose them: chain = flow:trans(x => x - 1, stepA( stepB( ink(2,5) ) )) # ... or partial usage, etc. # 4) Example partial usage => only define the transform function: myTrans = flow:trans(x => x * 10) sput( flow:to_array( myTrans( ink(1,4) ) ) ) # => [10,20,30]

If called with two arguments (userFunc, source), it returns a new InkTransform. The source can be an InkIterator or another InkTransform (chaining).

If fewer arguments or placeholders are provided, partial usage is returned until both a function and a source are known.

The user-defined function receives each item individually. If it returns an error or 'NO_MORE_DATA', iteration stops. Typical bridging expects a single transformed item per call.

Combine with flow:to_array(...) to gather all transformed items into an in-memory array.

transpose :gpu GPU

Transposes a 2D tensor on the GPU, swapping rows and columns.
extend("gpu") A = gpu:to_tensor([[1,2,3],[4,5,6]]) sput( gpu:transpose(A) ) # => [[1,4],[2,5],[3,6]] # Use cases: # 1) Reorienting matrices for multiplication or convolution. # 2) Converting row-major data to column-major or vice versa.

gpu:transpose expects exactly 1 Tensor. Must be 2D, shape [rows, cols].

Returns a new tensor with shape [cols, rows].

If input is not 2D, bridging may raise an error or produce unexpected results.

transpose :matrix Matrix PARTIAL

Returns the transpose of a 2D array (rows become columns, columns become rows). Supports partial usage for the matrix.
extend("matrix") # 1) Basic usage => 2×2 A = [[1,2],[3,4]] T = matrix:transpose(A) # => [[1,3],[2,4]] sput(T) # 2) Floats => same concept F = [[1.1,2.2],[3.3,4.4]] sput( matrix:transpose(F) ) # => [[1.1,3.3],[2.2,4.4]] # 3) Partial usage => only one argument is known part = matrix:transpose() res = part([[10,20],[30,40]]) sput(res) # => [[10,30],[20,40]] # If the array is not recognized as int2d or float2d, or dimension is 0, result or error depends on bridging.

Takes 0 or 1 arguments. If zero, partial usage is returned, expecting the actual 2D array next.

Returns a new 2D array with rows and columns swapped. If A is M×N, the result is N×M.

Works with int2d_array or float2d_array. If shape is irregular or data is not 2D, bridging might raise an error.

triangle :kanvas Kanvas

Draws a filled triangle defined by three corner points.
extend("kanvas") win = kanvas:create([ width:400, height:300 ]) kanvas:display(win) kanvas:triangle(win, [[50,50], [250,80], [120,200]], "#FF00FF")

Arguments:

- Window handle

- Three points: [[x0, y0], [x1, y1], [x2, y2]]

- Color string

Draws a filled triangle with the specified color.

trunc :math Math JSMath

Removes any fractional digits from a single numeric argument, effectively rounding toward 0.
extend("math") sput( math:trunc(3.99) ) # => 3 sput( math:trunc(-1.99) ) # => -1

Accepts exactly 1 numeric argument, returning an integer part of x (as float or int). Negative numbers move toward 0.

type :core Core Builtin

Returns a string describing the runtime type of the given value (e.g., "Int", "Str", "IntArray", "Fn").
# Built‑in ⇒ you don’t need extend("core") # Scalars sput( type(123) ) // => "Int" sput( type(3.14) ) // => "Float" sput( type("hello") ) // => "Str" sput( type(true) ) // => "Bool" # Collections sput( type([1,2,3]) ) // => "IntArray" sput( type([name:"Bob"]) ) // => "KeyedArray" # Functions f = x => x * 2 sput( type(f) ) // => "Fn"

Accepts **exactly one argument** of any `Value` type.

Returns a short string identifying that value’s runtime type. Common results include:

- "Int", "Float", "Bool", "Str"

- "IntArray", "StrArray", "BoolArray", "KeyedArray"

- "Fn" (any function or lambda)

If you pass the wrong number of arguments it raises an error immediately.

unique_filename :test TestUtility

Generates a pseudo-random path string in the 'tmp/' directory, useful for creating unique test files without collisions.
extend("test") # Basic usage: # test:unique_filename() path = test:unique_filename() sput(path) # => 'tmp/test_89ab2cd3' or similar # The function does not create or open the file; it just returns a unique path.

Accepts zero arguments, returns a single string in the form "tmp/test_<8_hex>" that is likely unique for this run.

Useful in tests to avoid name collisions when creating or overwriting files.

Does not actually create a file, only returns a path.

upper :string String

Converts a single string to uppercase.
extend("string") sput( string:upper("Hello, world!") ) // => "HELLO, WORLD!" # If you pass anything other than a single string, it raises an error.

The function takes exactly one string argument and returns its uppercase equivalent.

It will fail if given something that is not a single string.

write :file FileIO PARTIAL

Writes data to a file. With one or two arguments, writes the entire string at once. If a streaming callback is provided, writes chunk by chunk until you signal completion.
# 1) Basic usage (two arguments): write an entire file at once. extend("file") file:write("/path/to/output.txt", "Hello, world! ") # => If successful, returns true (or 'OK'). # If an error occurs (permissions, full disk), raises an error.
# 2) Streaming usage (three arguments: path, initDataOrNil, chunkCallback) # If your environment supports streaming writes, pass a callback. file:write("/path/to/log.txt", null, chunkSupplier => { # chunkSupplier is a function you call to get the next chunk to write. # or your bridging environment might repeatedly call chunkSupplier to pull data. # Example usage: # for each chunk, return a string. If no more data, return false or an empty string. chunk = array:shift(myChunkQueue) if chunk == _ then return false # no more data return chunk # write this chunk }) # => The function might block or run asynchronously while chunks are written. # Once you return false or empty from your chunkSupplier, the file is closed.
# 3) Partial usage => placeholders # If your environment supports partial usage, you can do: myPartialWrite = file:write("/tmp/data.txt", _) # Then call that with the content or callback. myPartialWrite("Hello!") # Or fix the data, waiting for the file path.

Argument patterns: - (path:string, textToWrite:string): writes the given string to that path all at once. - (path:string, something, callback:function): if streaming is supported, the callback is used to obtain successive chunks.

If the file does not exist, it is created. If it does exist, it’s overwritten unless your environment defaults to append mode.

Returns a boolean true or a success message (e.g. "OK"). Raises an error if writing fails.

Partial usage is possible, e.g. `file:write(path, _)` or `_` placeholders.

If your bridging layer does not implement streaming, the third argument and chunk callback references can be omitted or raise an error.