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 effect.
Operators
Arithmetic
+ - * / %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
&& || !Natural-language: and, or, not.
Ternary
condition ? valueIfTrue : valueIfFalseLet 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
| 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
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
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 |
.filter(fn) | Keep elements that match |
.reject(fn) | Remove elements that match |
.reduce(fn, init) | Accumulate a value |
.find(fn) | First matching element |
.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
| 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
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.
| Function | Description |
|---|---|
Object.keys(obj) | Array of keys |
Object.values(obj) | Array of values |
Object.entries(obj) | Array of [key, value] pairs |
Object.fromEntries(pairs) | Object from [key, value] pairs |
Object.merge(a, b) | Merge two objects (b overrides a) |
Object.hasKey(obj, key) | Check if key exists |
Object.get(obj, key) | Get value by key |
Object.delete(obj, key) | Remove a key |
Math
| Function | Description |
|---|---|
Math.round(x) | Round to nearest integer |
Math.round(x, n) | Round to N decimal places |
Math.ceil(x) / Math.floor(x) | Round up / down |
Math.abs(x) / Math.sign(x) | Absolute value / sign |
Math.pow(base, exp) | Exponentiation |
Math.sqrt(x) / Math.log(x) | Square root / natural log |
Math.min(a, b) / Math.max(a, b) | Minimum / maximum |
Math.random() | Random number 0-1 |
Math.PI / Math.E | Constants |
Math.sin(x), cos, tan, asin, acos, atan | Trigonometry |
Formatting (Intl)
Format values for display. Returns strings, not numbers.
compute display let price = Intl.formatNumber(input.amount, {decimals: 2}) // "1,234.50" let rate = Intl.formatNumber(input.percentage, {style: "percent"}) // "18%" let date = Intl.formatDate(input.timestamp, {style: "date"}) // "2026-06-09" {price: price, rate: rate, date: date}| Function | Description |
|---|---|
Intl.formatNumber(x) | Format with thousands separator |
Intl.formatNumber(x, {decimals: n}) | Fixed decimal places |
Intl.formatNumber(x, {style: "percent"}) | Percentage format |
Intl.formatDate(iso) | Short date format |
Intl.formatDate(iso, {style: "iso"}) | Full ISO 8601 |
Intl.formatDate(iso, {style: "date"}) | Date only |
Intl.formatDate(iso, {style: "time"}) | Time only |
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 |
JSON
| Function | Description |
|---|---|
JSON.parse(str) | Parse JSON string to object |
JSON.stringify(obj) | Convert object to JSON string |
Practical examples
Conditional formatting
compute format_price let amount = input.price { display: amount > 1000 ? "$" + Math.round(amount / 1000, 1) + "k" : "$" + Math.round(amount, 2), tier: amount > 10000 ? "enterprise" : amount > 1000 ? "business" : "starter" }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
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
computesteps: the entire body is an expressiondecideconditions:when <expression>with taskstrings:${expression}interpolation- Step configuration: values in
returns,assuming, field defaults
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
- Computation - Compute steps in depth
- Decisions - Using expressions in decide conditions
- compute reference - Full specification