Basic Tips
-
N
and M
suffixes on numeric literals create BigInt
and BigDecimal
values, respectively. Clojure BigInt
is distinct from Java BigInteger
, but you can convert with the biginteger
fn.
-
The return value of def
can be deref
ed, e.g. @(def x 1)
.
-
recur
also works in fn
s, including #( )
.
-
Babashka provides these namespace aliases:
clojure.set
as set
clojure.string
as str
-
Many JDK classes and methods are available. See Babashka's classes.clj for an exact list.
I/O
- Use
prn
instead of println
for numbers and symbols.
doto
can be useful for printing complicated intermediate expressions.
- Often you can use a quoted symbol instead of a string, e.g.
"Fizz"
=> 'Fizz
.
- A Lisp formatter implementation is available as
clojure.pprint/cl-format
. It can be useful in some situations, despite the long name.
Reference
Looping
There are many of ways to loop in Clojure. Here's some advice on when to use what:
- To loop a fixed number of times for side effects, use
dotimes
.
- If you're using a constant, a character literal can be used instead of an integer, which sometimes saves bytes and/or chars.
- To loop over a sequence for side effects, use
doseq
.
- Use a single
doseq
for nested loops over multiple sequences.
run!
can be situationally occasionally useful too.
- To produce a sequence, then use
map
/filter
/keep
/etc.
for
can be situationally useful too.
- To loop with one state variable, use
nth
and iterate
.
- To loop over a sequence with one state variable, use
reduce
.
- Sometimes you can save by using the two-argument version.
- Otherwise, use recursion
- Ideally an anonymous short function with
recur
. This requires tail recursion and doesn't allow nesting with other short functions.
- Even a non-short function is better than
loop
.
Ironically, the loop
macro is never optimal.
Handling Arguments
(mapv #(println %)*command-line-args*)
(doseq[a *command-line-args*](println a))
Usually mapv
is best, but doseq
is better when you have other nested short fns.
Indexing
There're a few different ways to get a value from a sequence:
(ds idx) ; Shortest, but only works for vectors, sets, and maps; no default and errors when out of range
(ds idx default?) ; Has default, but only works for maps
(get ds idx default?) ; Nil/default when out of range, but only for indexed sequences
(nth ds idx) ; Works for all sequences, even lazy ones
Conditionals
(if cond x y) ; Short circuits, you can leave the false section out to return nil, needs a truthy or (falsey/nil) condition
(and/or cond x) ; Short circuits, multiple conditions
(case n v x default) ; Short circuits, checks specific values, has default
({v x}n default) ; Same as case, but no short circuit
([x y]n) ; Needs a numeric 0/1 condition
(get[x y]n default) ; 0/1 condition or non-short-circuiting default
Syntax-quoting
Syntax-quoting can be used instead of sequence fns in a variety of cases:
(concat a b)
; vs
`(~@a~@b)
(cons a b)
; vs
`(~a~@b)
All sequences can be spliced inside syntax-quoting, including strings, sets, maps, and nil
.
Vector and set literals can also be used:
(conj s a)
; vs
`#{~@s~a}
; vs
`[~@s~a]
Map literals work too, but require an even number of forms inside.