Syntax Cheat Sheet

A dense single-page reference covering all syntax forms, operators, common patterns, and key prelude functions.

Primitives

TypeSyntaxExamples
Integerdigits42, -7, 0
Floatdigits with .3.14, -0.5
Stringdouble quotes"hello", "line\nbreak"
Symbolcolon prefix:key, :name
Booleanliteralstrue, false
Nullliteralnull
ZDTt"..." prefixt"2024-03-15", t"2024-03-15T14:30:00Z"

Blocks

# Property declaration
name: expression

# Function declaration
f(x, y): expression

# Operator declaration (binary)
(l ++ r): expression

# Operator declaration (prefix / postfix)
(! x): expression
(x ******): expression

# Block literal
{ a: 1 b: 2 c: 3 }

# Commas are optional
{ a: 1, b: 2, c: 3 }

# Nested blocks
{ outer: { inner: "value" } }

Top-level unit: the file itself is an implicit block (no braces needed).

Lists

# List literal
[1, 2, 3]

# Empty list
[]

# Mixed types
[1, "two", :three, true]

String Interpolation

# Insert expressions with {braces}
"Hello, {name}!"

# String anaphora (defines a function)
"#{}"           # one-parameter function
"{0} and {1}"   # two-parameter function

Comments

# Line comment (to end of line)
x: 42 # inline comment

Declarations

FormSyntaxNotes
Propertyname: exprDefines a named value
Functionf(x, y): exprNamed function with parameters
Block patternf({x y}): exprDestructures block argument fields
Block renamef({x: a y: b}): exprDestructures with renamed bindings
List patternf([a, b, c]): exprDestructures fixed-length list
Cons patternf([h : t]): exprDestructures head and tail of list
Binary operator(l op r): exprInfix operator
Prefix operator(op x): exprUnary prefix
Postfix operator(x op): exprUnary postfix
Idiot bracket⟦ x ⟧: exprCustom Unicode bracket pair

Idiot Brackets

Idiot brackets allow custom Unicode bracket pairs to wrap and transform expressions — a general bracket overloading mechanism.

# Declare a bracket pair function
⟦ x ⟧: my-functor(x)

# Use the bracket pair in expressions
result: ⟦ some-expression ⟧  # calls my-functor(some-expression)

Built-in bracket pairs: ⟦⟧, ⟨⟩, ⟪⟫, ⌈⌉, ⌊⌋, ⦃⦄, ⦇⦈, ⦉⦊, «», 【】, 〔〕, 〖〗, 〘〙, 〚〛.

Monadic Blocks

Monadic sequencing (like do-notation) is supported via bracket pairs or block metadata. A bracket block or annotated block followed by .expr desugars to a bind chain.

# Bracket pair definition — explicit functions
⟦{}⟧: { :monad bind: my-bind  return: my-return }

# Bracket pair definition — namespace reference
⟦{}⟧: { :monad namespace: my-monad }

# Block metadata forms (all followed by .return_expr):
{ :name decls }.expr                          # Form 1: bare symbol namespace
{ { monad: name } decls }.expr               # Form 2: monad key
{ { :monad namespace: name } decls }.expr    # Form 3: tagged namespace
{ { :monad bind: f return: r } decls }.expr  # Form 4: explicit inline

# ⟦ a: ma  b: mb ⟧.return_expr
# desugars to: bind(ma, (a): bind(mb, (b): return(return_expr)))
result: ⟦ a: ma  b: mb ⟧.(a + b)

All declarations are bind steps whose names are in scope for later declarations and the return expression. The return expression follows the closing bracket (or block) as .name, .(expr), or .[list].

Metadata Annotations

# Declaration metadata (backtick prefix)
` "Documentation string"
name: value

# Structured metadata
` { doc: "description" associates: :left precedence: 50 }
(l op r): expr

# Unit-level metadata (first expression in file)
{ :doc "Unit description" }
a: 1

Special metadata keys: :target, :suppress, :main, associates, precedence, import.

Function Application

# Parenthesised application (no whitespace before paren)
f(x, y)

# Catenation (pipeline style, single argument)
x f              # equivalent to f(x)
x f g h          # equivalent to h(g(f(x)))

# Partial application (curried)
add(1)           # returns a function adding 1

# Sections (operator with gaps)
(+ 1)            # function: add 1
(* 2)            # function: multiply by 2
(/)              # function: floor divide (two params)
(÷)              # function: precise divide (two params)

Lookup and Generalised Lookup

# Simple lookup
block.key

# Generalised lookup (evaluate RHS in block's scope)
{ a: 3 b: 4 }.(a + b)        # 7
{ a: 3 b: 4 }.[a, b]         # [3, 4]
{ a: 3 b: 4 }."{a} and {b}"  # "3 and 4"

Anaphora (Implicit Parameters)

TypeNumberedUnnumberedScope
Expression_0, _1, _2_ (each use = new param)Expression
Block•0, •1, •2 (each use = new param)Block
String{0}, {1}, {2}{} (each use = new param)String
# Expression anaphora
map(_0 * _0)        # square each element
map(_ + 1)          # increment (each _ is a new param)

# Block anaphora (bullet = Option-8 on Mac)
{ x: •0 y: •1 }    # two-parameter block function

# String anaphora
map("item: {}")     # format each element

Operator Precedence Table

From highest to lowest binding:

PrecNameAssocOperatorsDescription
95--prefixTight prefix (head)
90lookupleft.Field access / lookup
88bool-unaryprefix!, ¬Boolean negation
88bool-unarypostfixNot-null check (true if not null)
85expright^, , ;Power, composition
80prodleft*, /, ÷, %Multiplication, floor division, precise division, floor modulo
75sumleft+, -Addition, subtraction
55--rightList cons (prepend element)
50cmpleft<, >, <=, >=Comparison
45appendright++, <<List append, deep merge
42mapleft<$>Functor map
40eqleft=, !=Equality
35bool-prodleft&&, Logical AND
30bool-sumleft||, Logical OR
20catleft(catenation)Juxtaposition / pipeline
10applyright@Function application
5metaright//, //<< , //=, //=>Metadata / assertions

User-defined operators default to left-associative, precedence 50. Set custom values via metadata: ` { precedence: 75 associates: :right }

Named precedence levels for use in metadata: lookup, call, bool-unary, exp, prod, sum, shift, bitwise, cmp, append, map, eq, bool-prod, bool-sum, cat, apply, meta.

Block Merge

# Catenation of blocks performs a shallow merge
{ a: 1 } { b: 2 }       # { a: 1 b: 2 }
{ a: 1 } { a: 2 }       # { a: 2 }

# Deep merge operator
{ a: { x: 1 } } << { a: { y: 2 } }  # { a: { x: 1 y: 2 } }

Imports

# Unit-level import
{ import: "lib.eu" }

# Named import
{ import: "cfg=config.eu" }

# Multiple imports
{ import: ["dep-a.eu", "dep-b.eu"] }

# Format override
{ import: "yaml@data.txt" }

# Git import
{ import: { git: "https://..." commit: "sha..." import: "file.eu" } }

Key Prelude Functions

Lists

FunctionDescription
headFirst element
tailAll but first
cons(x, xs)Prepend element
map(f)Transform each element
filter(p?)Keep elements matching predicate
foldl(f, init)Left fold
foldr(f, init)Right fold
sort-by(f)Sort by key function
take(n)First n elements
drop(n)Remove first n
zipPair elements from two lists
zip-with(f)Combine elements with function
flattenFlatten nested lists one level
reverseReverse a list
countNumber of elements
range(a, b)Integers from a to b-1
nil?Is the list empty?
any?(p?)Does any element match?
all?(p?)Do all elements match?
uniqueRemove duplicates

Blocks

FunctionDescription
lookup(key)Look up a key (symbol)
lookup-or(key, default)Look up with default
has(key)Does block contain key?
keysList of keys (as symbols)
valuesList of values
elementsList of {key, value} pairs
map-keys(f)Transform keys
map-values(f)Transform values
select(keys)Keep only listed keys
dissoc(keys)Remove listed keys
merge(b)Shallow merge
deep-merge(b)Deep recursive merge
sort-keysSort by key name

Strings (str namespace)

FunctionDescription
str.len(s)String length
str.upper(s)Upper case
str.lower(s)Lower case
str.starts-with?(prefix)Starts with prefix?
str.ends-with?(suffix)Ends with suffix?
str.contains?(sub)Contains substring?
str.matches?(regex)Matches regex?
str.split(sep)Split by separator
str.join(sep)Join list with separator
str.replace(from, to)Replace occurrences
str.trimRemove surrounding whitespace

Serialisation and Parsing

FunctionDescription
render(value)Serialise to YAML string
render-as(fmt, value)Serialise to string in named format
parse-as(fmt, str)Parse string as structured data (inverse of render-as)

Formats for render-as: :yaml, :json, :toml, :text, :edn, :html. Formats for parse-as: :json, :yaml, :toml, :csv, :xml, :edn, :jsonl.

parse-as is safe for untrusted input — YAML !eu tags are never evaluated.

Combinators

FunctionDescription
identityReturns its argument unchanged
const(k)Always returns k
compose(f, g) or f ∘ gCompose functions
flip(f)Swap argument order
complement(p?)Negate a predicate
curry(f)Curry a function taking a pair
uncurry(f)Uncurry to take a pair

Numbers

FunctionDescription
numParse string to number
absAbsolute value
negateNegate number
inc / decIncrement / decrement
max(a, b) / min(a, b)Maximum / minimum
even? / odd?Parity predicates
zero? / pos? / neg?Sign predicates
floor / ceil / roundRounding

Arrays (arr namespace)

FunctionDescription
arr.zeros(shape)Create array of zeros; shape is a list of integers
arr.fill(shape, val)Create array filled with val
arr.from-flat(shape, vals)Create array from flat list of numbers
arr.get(a, coords)Element at coordinate list coords
arr.set(a, coords, val)New array with element at coords set to val
arr.shape(a)Shape as list of integers
arr.rank(a)Number of dimensions
arr.length(a)Total number of elements
arr.to-list(a)Flat list of elements in row-major order
arr.array?(x) / is-array?(x)Is x an array?
arr.transpose(a)Reverse all axes
arr.reshape(a, shape)Reshape (total elements must match)
arr.slice(a, axis, idx)Slice along axis at idx (reduces rank by 1)
arr.add(a, b) / arr.sub / arr.mul / arr.divElement-wise arithmetic; b may be scalar
a !! coordsIndex operator; for arrays, coords is a list e.g. [row, col]
arr.indices(a)List of coordinate lists for every element (row-major)
arr.map(f, a)Apply f to each element; same shape
arr.map-indexed(f, a)Apply f(coords, val) to each element; same shape
arr.fold(f, init, a)Left-fold over all elements in row-major order
arr.neighbours(a, coords, offsets)Values at valid in-bounds neighbours given offset vectors

The standard +, -, *, / operators are polymorphic and apply element-wise when either operand is an array. Scalar broadcasting is supported.

IO

Binding / FunctionDescription
io.envBlock of environment variables
io.epoch-timeUnix timestamp at launch
io.argsCommand-line arguments (after --)
io.randomInfinite lazy stream of random floats
io.RANDOM_SEEDCurrent random seed
io.return(a)Wrap a pure value in the IO monad
io.bind(action, cont)Sequence two IO actions
io.shell(cmd)Run cmd via sh -c; returns {stdout, stderr, exit-code}
io.shell-with(opts, cmd)Run cmd with extra options (e.g. {stdin: s, timeout: 60}). Pipeline: "cmd" shell-with(opts)
io.exec([cmd : args])Run cmd directly (no shell); argument is a list [cmd, arg1, arg2, ...]
io.exec-with(opts, [cmd : args])Run cmd directly with extra options. Pipeline: ["git", "log"] exec-with(opts)
io.check(result)Fail with stderr if exit-code is non-zero; otherwise return result
io.map(f, action)Apply pure function to result of IO action (fmap)

Assertion Operators

OperatorDescription
e //=> vAssert e equals v (panic if not)
e //= vAssert equals (silent, returns e)
e //!Assert e is true
e //!!Assert e is false
e //=? fAssert f(e) is true
e //!? fAssert f(e) is false

Command Line Quick Reference

eu file.eu                  # Evaluate file, output YAML
eu -j file.eu               # Output JSON
eu -x text file.eu          # Output plain text
eu -e 'expression'          # Evaluate expression
eu a.yaml b.eu              # Merge inputs
eu -t target file.eu        # Render specific target
eu list-targets file.eu     # List targets
eu --seed 42 file.eu        # Deterministic random
eu -Q file.eu               # Suppress prelude
eu fmt file.eu              # Format source
eu dump stg file.eu         # Dump STG syntax
eu -- arg1 arg2             # Pass arguments (io.args)