Complete syntax reference for writing .beme code.
Parentheses after a symbol, keyword, or vector form a call — spacing is irrelevant. The preceding element becomes the head of a Clojure list.
f(x y) → (f x y)
+(1 2 3) → (+ 1 2 3)
Spacing is irrelevant: foo(x) and foo (x) are both calls — the head is outside the parens.
Keywords work too: :active(m) → (:active m) (keyword-as-function).
Vectors can be heads: [x](body) → ([x] body) (used for multi-arity clauses).
Maps and sets can also be heads (they are functions in Clojure): {:a 1}(:a) → ({:a 1} :a), #{:a :b}(x) → (#{:a :b} x).
The head of a list is written outside the parens. Spacing between the head and ( does not matter:
foo(x) ;; call: (foo x)
foo (x) ;; also a call: (foo x)
begin and end can replace parentheses as call delimiters:
f begin x y end → (f x y)
These are equivalent to f(x y) — the head is still outside the delimiters. Useful for multi-line blocks where parentheses feel noisy:
defn begin greet [name]
println(str("Hello " name))
end
try begin
dangerous-operation()
catch(Exception e handle(e))
end
end is reserved inside begin blocks. Inside a begin block, the symbol end closes the block — it cannot appear as a data value. Outside begin blocks, end is a normal symbol.
Printer emits parens. The printer always outputs f(args...) — code written with begin/end round-trips semantically but not textually.
def(x 42)
def(state atom({:count 0}))
let([x 1, y +(x 1)] *(x y))
Produces: (let [x 1 y (+ x 1)] (* x y))
Destructuring works:
let([{:keys [id name]} person] println(id name))
Single arity:
defn(greet [name] println(str("Hello " name)))
Multiple body forms:
defn(greet [name] println(str("Hello " name)) name)
With docstring:
defn(greet "Greets a person" [name] println(str("Hello " name)))
Multi-arity:
defn(greet
[name](greet(name "!"))
[name punct](println(str("Hello " name punct))))
fn([x] +(x 1))
fn([x y] *(x y))
fn([acc item] assoc(acc :id(item) :balance(item)))
Multi-arity anonymous function (vector-as-head for each clause):
fn([x](+(x 1))
[x y](+(x y)))
defn-(helper [x] +(x 1))
Macros work in .beme files. Syntax-quote (`) is an opaque boundary —
the template inside backtick is raw Clojure, passed to Clojure's reader.
defmacro(my-log [tag expr] list('println tag expr))
defmacro(unless [test & body] `(if (not ~test) (do ~@body)))
if(>(x 0) "positive" "negative")
if(>(x 0) "positive")
when(>(x 0) println("positive"))
when(>(x 0) println("positive") do-something(x))
cond(
>(x 0) "positive"
==(x 0) "zero"
:else "negative")
case(x
1 "one"
2 "two"
"default")
loop([i 0, acc []]
if(>=(i 10)
acc
recur(inc(i) conj(acc i))))
for([x xs, y ys, :when >(x y)] [x y])
Produces: (for [x xs y ys :when (> x y)] [x y])
Modifiers :when, :while, and :let are passed through:
for([x xs, :let [y *(x 10)], :while <(y 100)] y)
Same binding syntax as for, but for side effects:
doseq([x items, :when active?(x)] println(x))
try(
dangerous-operation()
catch(Exception e log/error("Failed:" e) default-value)
finally(cleanup()))
catch and finally are regular calls inside try's arguments.
Threading macros are just calls:
->(account update(:balance *(1.05)) assoc(:status :processed))
->>(accounts filter(:active) map(:balance) reduce(+))
Multi-line:
->>(accounts
filter(:active)
map(fn([a] update(a :balance *(:balance(a) 1.05))))
remove(fn([a] neg?(:balance(a))))
reduce(+ 0))
ns(my.accounts
:require(
[clojure.string :as str]
[clojure.set :as set]
[my.db :refer [query connect]])
:import(
[java.util Date UUID]))
.toUpperCase("hello") ;; method call
Math/abs(-1) ;; static method
java.util.Date.() ;; constructor
.-x(point) ;; field access
def(state atom({:count 0}))
swap!(state update(:count inc))
@state
defprotocol(Drawable draw([this canvas]) bounds([this]))
defrecord(Circle [center radius])
defrecord(Circle [center radius]
Drawable
draw([this canvas] draw-circle(canvas this))
bounds([this] get-bounds(this)))
deftype(Point [x y])
deftype(Point [x y]
Drawable
draw([this canvas] render(canvas .-x(this) .-y(this))))
reify(Object toString([this] "hello"))
defmulti(area :shape)
defmethod(area :circle [{:keys [radius]}] *(Math/PI radius radius))
All of these work exactly as in Clojure:
[1 2 3], {:a 1}, #{1 2 3}, :keyword, "string"@deref, ^metadata, #'var, #_discard, 'quote#(inc(%)) → (fn [%1] (inc %1)), #(rand()) → (fn [] (rand)). Body must be a single expression. Uses beme syntax inside.#"pattern"\a, \newline, \space#inst, #uuid::foo — in the file runner, deferred to eval time so ::foo resolves in the file's declared namespace (not the caller's). In the REPL, resolved at read time (like Clojure). When using beme->forms directly without :resolve-keyword, deferred to eval time via (read-string "::foo"). On CLJS, :resolve-keyword is required (errors without it)#?(:clj x :cljs y) — passed through opaquely#:ns{}; comment'(x y z) — uses Clojure S-expression syntax inside. '(f (g x)) produces (quote (f (g x))). Inside '(...), parentheses create lists (no Rule 1 calls), so all Clojure forms are quotable. This is the only context where bare (...) is valid| Clojure | beme | Notes |
|---|---|---|
(f x y) | f(x y) | Parens follow the callable |
(f x y) | f begin x y end | Textual delimiters, equivalent to parens |
'(f (g x)) | '(f (g x)) | Quote uses S-expression syntax inside |
Quote uses Clojure syntax inside. '(f (g x)) produces (quote (f (g x))).
Inside '(...), parentheses create lists — Rule 1 is suspended. This means
all Clojure forms are quotable, including lists with non-callable heads like
'((1 2) (3 4)). Outside '(...), quote on non-lists works normally: 'foo,
'42, ':kw.
Backtick is opaque. Syntax-quote (`) and its body are raw Clojure,
passed to Clojure's reader. Macro templates use S-expressions inside backtick;
beme syntax applies everywhere else.
#() uses beme syntax inside. #(inc(%)) is (fn [%1] (inc %1)).
The call rule applies normally within #(). Use %, %1, %2 for
params.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |