Expressions
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
mashin has a built-in expression language used inside compute steps, decide conditions, and ${...} interpolation in task strings. It is JavaScript-inspired: if you know JS, you already know most of it. The key difference is that expressions are pure. There are no I/O primitives, no fetch(), no console.log(). Expressions compute; machines act.
Operators
Section titled “Operators”Arithmetic
Section titled “Arithmetic”+ - * / %Comparison
Section titled “Comparison”== != > < >= <=In decide steps, you can also use natural-language operators: is, is not, is greater than, is less than, is at least, is at most.
Logical
Section titled “Logical”&& || !Natural-language: and, or, not.
Ternary
Section titled “Ternary”condition ? valueIfTrue : valueIfFalseLet bindings
Section titled “Let bindings”Bind intermediate values with let. Bindings are scoped to the current step:
compute analyze let count = input.items.length let total = input.items.reduce((sum, x) => sum + x.amount, 0) let average = total / count {count: count, total: total, average: average}The last expression in a step is its return value.
Data access
Section titled “Data access”| Reference | What it accesses |
|---|---|
input.<field> |
Machine input fields |
steps.<step_name>.<field> |
Output from a previous step |
context.<key> |
Execution context values |
state.<field> |
Machine state (reactive machines) |
event.<field> |
Incoming event data (in subscribes handlers) |
Dot access and bracket access both work: input.name and input["name"] are equivalent.
String interpolation
Section titled “String interpolation”Inside with task strings (and any string using ${}), expressions are evaluated and inserted:
ask classify, using: "anthropic:claude-sonnet-4-6" with task "Analyze this order.\n\nCustomer: ${input.customer_name}\nTotal: $${input.amount}\nItems: ${input.items.length}"Array methods
Section titled “Array methods”Arrays support the standard functional methods:
compute transform let names = input.users.map(u => u.name) let active = input.users.filter(u => u.active) let total = input.scores.reduce((sum, s) => sum + s, 0) let found = input.items.find(i => i.id == input.target_id) let has_admin = input.roles.includes("admin") { names: names, active_count: active.length, total_score: total, target: found, has_admin: has_admin }| Method | Description |
|---|---|
.map(fn) |
Transform each element |
.flatMap(fn) |
Map then flatten one level. A callback result that is not a list counts as one element, so [1, 2].flatMap(x => x) is [1, 2] and a null result contributes one null |
.filter(fn) |
Keep elements that match |
.reject(fn) |
Remove elements that match |
.reduce(fn, init) |
Accumulate a value |
.find(fn) |
First matching element |
.findIndex(fn) |
Index of the first matching element (-1 if none matches) |
.some(fn) / .any(fn) |
True if any element matches |
.every(fn) |
True if all elements match |
.includes(val) |
Check if value exists |
.indexOf(val) |
Index of first occurrence (-1 if not found) |
.sort() |
Sort elements |
.sortBy(fn) |
Sort by a key function |
.reverse() |
Reverse order |
.unique() / .uniq() |
Remove duplicates |
.uniqueBy(fn) |
Deduplicate by key function |
.groupBy(fn) |
Group into object by key function |
.flat() |
Flatten one level |
.concat(other) |
Concatenate two arrays |
.join(sep) |
Join elements into a string |
.take(n) |
First N elements |
.drop(n) |
All but first N elements |
.chunk(n) |
Split into chunks of size N |
.zip(other) |
Pair elements from two arrays |
.slice(start, end) |
Sub-array by index range |
.at(index) |
Element at index |
.count(fn) |
Count elements matching predicate |
.sum() |
Sum of numeric elements |
.min() / .max() |
Minimum / maximum element |
.first() / .last() |
First / last element |
.length |
Number of elements |
String methods
Section titled “String methods”| Method | Description |
|---|---|
.toUpperCase() / .toLowerCase() |
Case conversion |
.trim() |
Remove leading/trailing whitespace |
.trimStart() / .trimEnd() |
Remove whitespace from one end |
.split(separator) |
Split into array |
.replace(from, to) |
Replace first occurrence |
.replaceAll(from, to) |
Replace all occurrences |
.startsWith(s) / .endsWith(s) |
Check prefix/suffix |
.includes(s) |
Check if substring exists |
.padStart(n) / .padEnd(n) |
Pad to length |
.repeat(n) |
Repeat N times |
.substring(start, end) |
Extract substring |
.match(pattern) |
Regex match |
.test(pattern) |
Regex test (returns boolean) |
.length |
String length |
Objects
Section titled “Objects”Build objects with {} syntax. Use spread to merge:
compute merge let base = {status: "active", created: DateTime.now()} let details = {name: input.name, email: input.email} {...base, ...details}Access nested fields with dot notation: steps.analyze.results[0].name.
Objects carry their operations as methods. There is no Object namespace; writing
Object.keys(map) is an error that points you to the method form.
| Method | Description |
|---|---|
map.keys() |
Array of keys |
map.values() |
Array of values |
map.entries() |
Array of [key, value] pairs |
map.merge(other) |
Merge two objects (other overrides) |
map.has(key) |
Check if key exists |
map.delete(key) |
Remove a key |
Numbers
Section titled “Numbers”Numbers carry their operations as methods; two-value max and min take a list
receiver. There is no Math namespace; writing Math.abs(x) is an error that
points you to the method form.
| Method | Description |
|---|---|
x.round() |
Round to nearest integer |
x.round(n) |
Round to N decimal places |
x.ceil() / x.floor() |
Round up / down |
x.abs() / x.sign() |
Absolute value / sign |
x.pow(exp) |
Exponentiation |
x.sqrt() |
Square root |
[a, b].min() / [a, b].max() |
Minimum / maximum |
list.sum() |
Sum of a numeric list |
compute stats let rounded = input.price.round(2) let biggest = [input.a, input.b].max() {rounded: rounded, biggest: biggest}Formatting (format)
Section titled “Formatting (format)”Format values for display with the format namespace. Returns strings, not numbers.
compute display let price = format.number(input.amount, {decimals: 2}) // "1,234.50" let rate = format.number(input.percentage, {style: "percent"}) // "18%" let date = format.date(input.timestamp) // "Jun 9, 2026" {price: price, rate: rate, date: date}| Function | Description |
|---|---|
format.number(x) |
Format with thousands separator |
format.number(x, {decimals: n}) |
Fixed decimal places |
format.number(x, {style: "percent"}) |
Percentage format |
format.date(iso) |
Short date format |
format.date(iso, {style: "time"}) |
Time only |
DateTime
Section titled “DateTime”| Function | Description |
|---|---|
DateTime.now() |
Current ISO 8601 timestamp |
DateTime.today() |
Current date |
DateTime.parse(str) |
Parse ISO string |
DateTime.diff(a, b) |
Difference between datetimes |
DateTime.add(dt, amount) |
Add duration |
| Function | Description |
|---|---|
JSON.parse(str) |
Parse JSON string to object |
JSON.stringify(obj) |
Convert object to JSON string |
Practical examples
Section titled “Practical examples”Conditional formatting
Section titled “Conditional formatting”compute format_price let amount = input.price { display: amount > 1000 ? "$" + (amount / 1000).round(1) + "k" : "$" + amount.round(2), tier: amount > 10000 ? "enterprise" : amount > 1000 ? "business" : "starter" }Data reshaping
Section titled “Data reshaping”compute reshape let grouped = input.orders.reduce((acc, order) => { let key = order.status let existing = acc[key] || [] return {...acc, [key]: [...existing, order]} }, {}) {by_status: grouped, total: input.orders.length}Filtering and scoring
Section titled “Filtering and scoring”compute score_candidates let scored = input.candidates.map(c => ({ ...c, score: c.experience * 0.4 + c.test_result * 0.6 })) let qualified = scored.filter(c => c.score >= 70) { qualified: qualified, qualified_count: qualified.length, best: qualified.reduce((best, c) => c.score > best.score ? c : best, qualified[0]) }Where expressions are used
Section titled “Where expressions are used”computesteps: the entire body is an expressiondecideconditions:when <expression>with taskstrings:${expression}interpolation- Step configuration: values in
returns,assuming, field defaults
Try it
Section titled “Try it”Write a machine that accepts a list of numbers and uses a single compute step to return the count, sum, average, minimum, and maximum. Use let bindings for clarity.
Next steps
Section titled “Next steps”- Computation - Compute steps in depth
- Decisions - Using expressions in decide conditions
- compute reference - Full specification