{:check ["true"],
 :rank ["expressions" "top-level" "lambda-fn" "let" "references"]}

Index

Basic Syntax of Clojure

Expressions

Expressions and function invocation

  • Everything is an expression.
  • All expressions evaluate to a value.
In [2]:
42
Out[2]:
42
In [3]:
[1 2 3]
Out[3]:
[1 2 3]
In [4]:
+
Out[4]:
#function[clojure.core/+]

Lists are evaluated as computation.

  • Function invocation
  • Special forms for computational constructions. More on this later.
In [5]:
(+ 1 2)
Out[5]:
3
In [6]:
(concat [1 2] [3 4])
Out[6]:
(1 2 3 4)

Clojure encourages variadic arguments to functions. Most built-in functions take flexible number of arguments.

In [7]:
(+ 1 2 3 4 5)
Out[7]:
15
In [8]:
(+)
Out[8]:
0

Predicates are just functions returning boolean values.

In [9]:
(< 2 5)
Out[9]:
true
In [10]:
(< 5 2)
Out[10]:
false
In [11]:
(= 5 2)
Out[11]:
false
In [12]:
(< 0 1 2)
Out[12]:
true
In [13]:
(< 0 2 1)
Out[13]:
false
In [14]:
(not (< 0 2 1))
Out[14]:
true

Data expressions with function invocation

Since lists can nested anywhere, we can embed computation inside data expressions.

In [15]:
{:title (str "CSCI" "3055U")
 :year (inc 2019)
 :total-quizzes (- (+ 2 8) 3)}
Out[15]:
{:title "CSCI3055U", :year 2020, :total-quizzes 7}

Top-Level

Top-level binding

(def <name> <value>)
In [3]:
(def pi 3.1415)
Out[3]:
#'user/pi
In [4]:
(def r 5)
Out[4]:
#'user/r
In [5]:
(println "Area is" (* pi r r))
Area is 78.53750000000001
Out[5]:
nil
In [6]:
(format "Area is %.2f" (* pi r r))
Out[6]:
"Area is 78.54"

Lambda-Fn

Lambda Calculus

(fn [ <arguments>... ]
  <body-expression>)
In [7]:
(fn [r] (* 3.1415 r r))
Out[7]:
#function[user/eval5505/fn--5506]

Let's bind the area function to a global symbol, so we can use it.

In [8]:
(def area (fn [r] (* 3.1415 r r)))
Out[8]:
#'user/area
In [9]:
(area 5)
Out[9]:
78.53750000000001
In [10]:
(area 6)
Out[10]:
113.094

There is a special form to make it easier.

(defn <function-name>
    [ <arguments>... ]
    <body-expression>)
In [11]:
(defn area [r] (* 3.1415 r r))
Out[11]:
#'user/area
In [12]:
(area 5)
Out[12]:
78.53750000000001

Let

Local Symbol Binding

Not all symbols are at the top level. In fact, most symbols are not at top level. We can have local bindings using the form:

(let [<symbol> <expression>
      <symbol> <expression>]
    <body-expression>
    <body-expression>
    ...)
In [13]:
(let [first-name "Albert"
      last-name "Einstein"]
    (format "%s %s" first-name last-name))
Out[13]:
"Albert Einstein"
In [14]:
; Outside the (let ...) form, the symbol bindings are "gone".
(format "%s %s" first-name last-name)
Syntax error compiling at (REPL:2:1).
Unable to resolve symbol: first-name in this context
  Util.java:   221 clojure.lang.Util/runtimeException
   core.clj:  3214 clojure.core$eval/invokeStatic
   core.clj:  3210 clojure.core$eval/invoke
   main.clj:   437 clojure.main$repl$read_eval_print__9086$fn__9089/invoke
   main.clj:   458 clojure.main$repl$fn__9095/invoke
   main.clj:   368 clojure.main$repl/doInvoke
RestFn.java:  1523 clojure.lang.RestFn/invoke
   AFn.java:    22 clojure.lang.AFn/run
   AFn.java:    22 clojure.lang.AFn/run
Thread.java:   748 java.lang.Thread/run

Let's do some more complex computation using nested (let ...) local symbol bindings.

In [12]:
; - pprint is "pretty print"
; - We construct a hash-map using nested (let ...)
(clojure.pprint/pprint
 (let [first-name "Albert"
      last-name "Einstein"]
    {:first first-name
     :last last-name
     :biography (let [occupations ["Patent Clerk" "Physicist"]]
                    (str first-name " " last-name
                         " worked many jobs: "
                         (clojure.string/join " and " occupations)))}))
;
{:first "Albert",
 :last "Einstein",
 :biography
 "Albert Einstein worked many jobs: Patent Clerk and Physicist"}

References

References

  1. Programming Clojure: Section 2.3 and 2.4