Clojure: Basic Syntax
This page is WORK IN PROGRESS.
comma and space
comma can be used as separator.
;; comma can be used as separator ;; the following are equivalent (+ 1 2 3) ; 6 (+ 1, 2 , 3) ; 6
comment
Comment start with SEMICOLON to end of line.
; comment start with semicolon
;; by lisp convention ;; comment on a line by itself start with 2 semicolons (+ 3 4) ; comment after a expression start with one semicolon
Comment can also be written as (comment …)
, but the comment body must be a valid lisp syntax, cannot be any character.
This returns nil
.
;; comment can also be written as (comment …) (comment this is a block comment. (comment block comment can be nested.) )
;; comment body must be valid clojure syntax. ;; a semicolon by itself is not (comment : ) ;; compiler error
You usually use this form (comment …)
to comment out a block of Clojure code.
;; (comment …) is usually used to comment out block of code (comment (+ 3 4) )
printing
use pr
to print. It returns nil
.
(pr "aa" "bb" "cc") ; prints "aa" "bb" "cc"
prn
-
same as
pr
but with a newline at the end.
pr
and prn
prints in a machine-readable way. (that is, can be read back by Clojure.)
To print in a human friendly way, use print
and println
strings
"some string abc"
to join string (concatenate), use str
. clojure.core/str
;; join string (str "aa" "bb") ; "aabb" (str 3 " cats") ; "3 cats"
substring
(subs str start_index)
(subs str start_index end_index)
Index start at 0. Start index is inclusive. End index is exclusive.
;; get substring, starting at index 1. (subs "abcd" 1) ; "bcd" ;; get substring, with start/end indexes. (subs "abcd" 1 3) ; "bc"
Clojure string functions
For string functions, use the Clojure library clojure.string
.
clojure.string - Clojure v1.8 API documentation
Example of calling a function in clojure.string
namespace:
; calling function upper-case from namespace clojure.string (clojure.string/upper-case "bb") ; BB
Note: slash is used to separate name space.
Call Java's String Methods
Clojure itself doesn't have many string functions. It is common to call Java's methods in Clojure.
To call Java's string method, use the syntax
(. java_object method_name args)
.
For example, there's Java String method named charAt
. To use it, do:
;; call Java method on object (. "abc" charAt 1) ; \b
A more commonly used syntax to call Java method is
(.method_name java_object args)
(.charAt "abc" 1) ; \b
[see Clojure: Call Java Method]
Numbers
Numbers can be written in the form baserdigits
. For example, the binary number 10
can be written as 2r10
, and the hexadecimal 1a
can be written as 16r1a
;; binary number input 2r1111 ; 15 ;; hexadecimal number input 16r1af ; 431 0x1af ; 431 (this form is from Java) ;; oct number input 8r77 ; 63 ;; base 36. using 0 to and a to z as digits 36rj7 ; 691
Arithmetic
;; addition, plus (+ 3 4) ;; substraction, minus (- 7 4) ;; can have 3 or more args (- 7 4 1) ;; multiply, times (* 2 4)
Here's division, quotient, remainder/mod, and ratio.
;; division (/ 7 4) ; 7/4 return a ratio. A Clojure datatype (/ 7 4.) ; 1.75 ;; integer quotient (quot 11 4) ; 2 ;; remainder (aka mod) (rem 11 4) ; 3
Closure does not have a math lib bundled.
To use math function such as sine, use Java's Math class. Like this: (Math/methodName arg)
;; exponentiation. 2 to the power of 3 (Math/pow 2 3) ; 8.0
[see Clojure: Call Java Method]
Converting String and Numbers
;; convert string to number (bigint "123")
;; convert number to string (str 123)
Codepoint to Character
;; unicode codepoint (integer) to char (char 97) ; a
Comparison Functions
(< 3 7) ; true (<= 3 7) ; true (> 3 7) ; false (>= 3 7) ; false
logic operations:
;; boolean and (and true false) ; false ;; boolean or (or true false) ; true ;; boolean not (not true) ; false
Block of Expressions
Sometimes you need to group several expressions together as one single expression. This can be done with do
. (“do” is like lisp's “progn”)
(do (pr "a") (pr "b")) ;; is equivalent to (pr "a") (pr "b")
Most of the time it's used inside “if”. clojure.core/if
For example:
(if something (do ; true … ) (do ; else … ) )
do
returns the last expression in its body.
(do 3 4 ) ; 4
define global variable
Use def
to set a value to a variable. Variable does not need to be declared.
;; define a var (def x 3) x ; 3
def
can be used to change a variable's value.
;; define a var (def x 3) (pr x) ; 3 ;; reset to 4 (def x 4) (pr x) ; 4
Local Constants: let
To create local constants, use let
. It has this form
(let [var1 val1 var2 val2 …] body)
(let [x 3] x) ; 3
(def x 4) (let [x 3] (pr x) ) ; 3 (pr x) ; 4
You can bind multiple variables:
(let [x 3 y 4] (+ x y)) ; 7
Later variable can use values of previous variables:
(let [x 3 y x] (+ x y)) ; 6
the value part can be any expression.
(let [x 3 y (+ 2 x)] (+ x y)) ; 8
Binding Form
The first arg of let
is called “binding form”. It is also used in function definition. [see Clojure: Functions]
Clojure's binding form is very flexible. You can do Destructure Binding. [see Clojure: Binding Forms, Destructuring]
True and False
The following are builtin literals.
true
false
nil
Clojure nil
is Java's null
.
false
and nil
are false, everything else evaluates to true
in true/false context.
(if nil 1 2) ; 2
If Then Else
The form for if statement is: (if test body)
.
If you want a “else” part, the form is (if test true_body false_body)
. Use a (do …)
to group the bodies.
if
returns the value of the evaluated branch.
Example:
(if (< 3 2) 9 ) ; nil
(if (< 3 2) "yes" "no" ) ; "no"
(if nil 3 4 ) ; 4
Iteration
Here's basic functions related to iteration:
(for [i (range 7)] (inc i)) ; (1 2 3 4 5 6 7)
clojure.core/range clojure.core/inc
Recursion
A function that calls itself is called recursion.
In a function definition, If a function calls itself as exit, then such recursion is called tail recursion or linear recursion.
Linear recursion is not nested in nature. You can think of it as “pass and forget”.
What is the difference between tail-recursion and non-tail-recursion?
Tail recursion can be trivially expressed as iteration or linear loop.
In programing languages, some programing language automatically compile tail-recursion into a iteration. (so that, it saves memory, avoiding stackoverflow, etc.) Scheme (programming language) is the language most famous for enforcing the tail-recursion optimization into its compiler, by spec.
Clojure supports recursion. That is, function can call itself.
Clojure also supports manual tail-recursion using recur
. That is, the compiler optimize recursion that's linear into a iteration-like construct.
If the recursion is linear recursion, than you can call recur
at the place you want to call function itself. The advantage is that there'll be no limit on recursion depth.
Collection and Sequence: list, vector, hash table …
Clojure: Collections (List, Vector, Set, Map, etc), Sequence
Defining a Function
Clojure data types
Clojure is not typed. Variable doesn't have a type, value has type.
name | example | Java type used |
---|---|---|
number | 18 | java.lang.Number |
string | "some" | java.lang.String |
boolean | true , false | java.lang.Boolean |
char | \b , \c | java.lang.Character |
keyword | :xyz , :bb | clojure.lang.keyword |
nil | nil | null |
name | example | Java type used |
---|---|---|
list | '(3 "e" 7) | ◇ |
vector | [8 2 "h"] | ◇ |
map | {:mary 13 :john 20} | java.util.Map |
set | #{9 2 4} | java.util.Set |
Clojure Char Data Type Literal
- Newline (Line Feed; Unicode codepoint 10 in decimal) is
\newline
- Tab character (Unicode codepoint 9 in decimal) is
\tab
- Unicode character can be written as
\u4_digits_hex
. For example, α is\u03b1
(what about outside bmp?)
keywords
“keyword” is a primitive datatype in Clojure. Keywords are symbolic identifiers. Usually used as keys for hash table. It's like Ruby's “symbol”.
keywords starts with a :
, like this: :abc
To convert a string to keyword, use keyword
function.
keyword is also a function. The work on hasmap and return the corresponding value.
symbols
Clojure symbols is the same as other lisp “symbols”. Symbols are identifiers, but unlike identifier in other languages, Clojure's “symbol” can remain in a unevaluated form.
symbols, eval to themself. Like other lang's variables, but can hold eval.
but symbol is also a function, that can work on hashmap and look themself up.
symbols can include these characters: * + ! - _ ?
global settings often starts and end with a asterisk, for example: *max*
namespace
regex
states, transactions
- refs
-
{synchronous, coordinated}.
ref
- agents
-
{asynchronous, independent}.
agent
- atoms
-
{synchronous, independent}.
atom
- var
-
like global var.
def
“refs” is typical set variable.
(deref val)
is same as @val
transactions
“transactions” is like database transactions. Process inside a transaction happen together or not at all, there is no possibility of partial success. (this property is often called “atomicity”)
“transactions” are isolated. No 2 transactions see each other.
dosync
creates a transaction. Other wise it's similar to do
. clojure.core/dosync
ref-set
is for setting a ref. It can only be used within a transaction. clojure.core/ref-set
alter
is like ref-set
, except it takes a function and other args. clojure.core/alter
atom
atom is like ref, except it's rather for independent entities (update that do not need to be coordinated with others).
agents (asynchronous)
most useful.
thread-local state: var, def
validator and watch
understanding clojure
reader forms
- symbol
- literals
- lists
- vectors
- maps
- sets
- deftype, defrecord, constructor calls
symbols begin with a non-numeric character. Can contain 0 to 9, a to z, * + ! - _ ?
/ is used once to separate namespaces.
. has special meaning — it can be used one or more times in the middle of a symbol to designate a fully-qualified class name, for example, 「java.util.BitSet」, or in namespace names.
Symbols beginning or ending with . are reserved by Clojure.
Symbols containing / or . are said to be 'qualified'.
Symbols beginning or ending with : are reserved by Clojure. A symbol can contain one or more non-repeating ':'s.
- forms
-
lisps refer to its syntax units as “forms”. For example,
(+ 3 4)
is a form. Anything that returnsa value is a form. - literal
-
a form that eval to itself. String
"…"
, number, character\b
, are literals.true
,false
,nil
, are also literals. - symbol
-
Symbols are like other lang's identifiers, except that lisp symbol is a identity that can be held unevaluated and be manipulated in unevaluated state. For example, if x has value of 3 (
def x 3
), then'x
eval to the symbol “x” itself, not its value. Macros are possible because of this. (You can think of “symbol” as a string, a label, a identifier.) - expressions
-
a form made of other forms. Typically they are enclosed by brackets. For example, list
(…)
, vector[…]
, map{…}
. Normally, a form is a function in the form of a list 「(‹head› …)」. The first element is the symbol of the function. The rest are arguments, and are evaluated in order. - special form
-
a form that has different evaluation order or special in some other way. For example,
if
is a special form. http://clojure.org/special_forms