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.