SlideShare a Scribd company logo
Introduction to ClojureIntroduction to Clojure
Sidharth Khattri
Knoldus Software LLP
Sidharth Khattri
Knoldus Software LLP
● Clojure is a Functional Lisp (List Processing) which runs on JVM.
● It extends the principle of Code-as-Data system to include Maps and Vectors.
Everything in clojure is written inside a data structure referred to as the
S-expressions, i.e nested lists.
Eg: (/ 4 (+ 1 2)) => ?
● Clojure is a Functional Lisp (List Processing) which runs on JVM.
● It extends the principle of Code-as-Data system to include Maps and Vectors.
Everything in clojure is written inside a data structure referred to as the
S-expressions, i.e nested lists.
Eg: (/ 4 (+ 1 2)) => ?
Function Name Arguments
● Every operation in clojure is done using a Post-Fix notation
● Experimenting with clojure is quite easy. In order to get started with
clojure you need to follow the instructions on http://leiningen.org/ to
set up clojure environment on your system. Leningen is used for
project automation.
● Most popular IDE used for clojure is LightTable which can be
download from http://www.lighttable.com/
● You can fire up clojure's repl on linux terminal using:
lein repl or you can directly use a Live REPL in LightTable.
● You can also use clojure in Eclipse using CounterClockwise plugin.
● Everything that you need to know about clojure can be found in the
clojure cheatsheet at the following url: http://clojure.org/cheatsheet
● Even though a lot of parentheses can confuse programmers at first,
LightTable(IDE) can make programming in clojure really easy. A sample of
what usage of parentheses I'm talking about:
(filter #(if(zero? (rem % 3)) true) (map #(+ % 1) (range 10)))
=> ?
● The above code in LightTable should look something like this:
● Last line of a function can return another function, i.e a Higher Order
Function as illustrated in the following example:
(defn attribute [who?]
(if (= who? "superman")
#(str "Superman " %)
(fn[x] (str "Human " x))))
((attribute "superman") "Flying") => "Superman Flying"
(if 0
“Yee! True”
“Huh! False”) => ?
(if 1
“Yee! True”
“Huh! False”) => ?
Concept of truthy and falsy
(if 0
“Yee! True”
“Huh! False”) => “Yee! True”
(if 1
“Yee! True”
“Huh! False”) => “Yee! True”
Concept of truthy and falsy
Concept of truthy and falsy
Everything in clojure is true except false or nil
So,
(if nil
“Yee! True”
“Huh! False”) => “Huh! False”
Data Structures
● Clojure supports a number of data structures:
Lists, Vectors, Maps, Sets
● All clojure data structures are persistent data structures. Internally
they're implemented as a tree.
● Simplest way to define these data structures:
'(1 2 3) defines a list
[1 2 3] defines a vector
#{1 2 3} defines a set
{:1 “one” :2 “two”} defines a map
Nesting
● Searching and updating nested structures is very easy.
● Searching:
(def n {:india {:newdelhi {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}}}
:usa {:california {:knoldus {:address "743, Catamaran Street "}}}})
user=> (get-in n [:india :newdelhi])
Returns {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}}
● Updating:
(assoc-in n [:india :newdelhi :knoldus :number] 911142316525)
Returns {:india {:newdelhi {:knoldus {:number 911142316525, :address "30/29, 1st Floor, East Patel
Nagar"}}}, :usa {:california {:knoldus {:address "743, Catamaran Street "}}}}
● Remember that the value of “n” hasn't changed in any case.
Threading Operators
The previous code that we used:
(filter #(if(zero? (rem % 3)) true) (map #(+ % 1) (range 10)))
Is same as:
(->> (range 10)
(map #(+ % 1))
(filter #(if (zero? (rem % 3)) true)))
The threaded version is much cleaner
Threading Operators
In Nested structures example that we used:
(def n {:india {:newdelhi {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}}}
:usa {:california {:knoldus {:address "743, Catamaran Street "}}}})
We can use:
(-> n :india :newdelhi :knoldus :address)
Instead of:
(:address (:knoldus (:newdelhi (:india n))))
Loops
● For loop:
(for [x (range 1 10) :when (even? x)] x)
=> (2 4 6 8)
● While loop:
(while 0 (println “hello”))
● Loops with side effects:
(dotimes [x 5] (print x)) => 01234nil
(doseq [x [3 2 1]] (print x)) => 321nil
Binding Form - let
● We use the “let” form to bind data structures to symbols.
● Example:
(let [x 10
y 11
m (* x y)]
m)
user=> m
Binding Form - let
● We can also use let binding for destructuring:
● (defn index-sum [v & i]
(let [[x :as ind] (map #(get v %) i)]
(reduce + ind)))
(index-sum [1 2 3 4 5 6 7 8 9] 1 3 5) => ?
Built-in Parallelism
● “map” function will take more time as compared to the “pmap” function:
(time (doall (map (fn[x] (Thread/sleep 3000) (+ x 5)) (range 1 5))))
=> "Elapsed time: 12000.99432 msecs"
(6 7 8 9)
(time (doall (pmap (fn[x] (Thread/sleep 3000) (+ x 5)) (range 1 5))))
=> "Elapsed time: 3002.989534 msecs"
(6 7 8 9)
Futures
● Futures can be used to send any calculation intensive work in the
background while continuing with some other work.
● Defining futures:
(def f (future some-calculation-intensive-work))
● Example:
(defn show-result[]
;;do things
(def f (future some-calculation-intensive-work))
;;prepare gui to display result
@f) ;;wait until the result is returned
Atoms, refs and agents
● Atoms, refs and agents are the three options available for maintaining non-
local mutable state in clojure
➔ Atoms are for Uncoordinated Synchronous access
to a single Identity.
➔ Refs are for Coordinated Synchronous access
to Many Identities.
➔ Agents are for Uncoordinated Asynchronous access
to a single Identity.
Atoms
● Defining an atom:
(def a (atom {:a 1}))
● Getting the value stored in an atom:
(deref a) or @a
● Changing the value of an atom:
(swap! a #(assoc % :b 2)) => {:a 1 :b 2}
or
(reset! a 0) => Exception or changed value?
Refs
● Defining refs:
(def tasks-to-be-done (ref #{2 9 4}))
(def tasks-done (ref #{1 3 5}))
● Coordinated change:
(dosync
(commute tasks-to-be-done disj 2)
(commute tasks-done conj 2))
● Accessing values of refs:
@tasks-to-be-done => #{4 9}
@tasks-to-be-done => #{1 2 3 5}
Agents
● Can be useful in fork/join solutions.
● Defining an agent:
(def a (agent 0))
● Dispatching actions to an agent:
(dotimes [x 3] (send-off a (fn[x] (Thread/sleep 3000) (inc x))))
@a => ?
● In case we want to wait until the above code snippet has finished processing,
we can use:
(await a)
Arrays
● Defining an array:
(def a1 (make-array Integer/TYPE 3))
(pprint a1) => [0, 0, 0]
(def a2 (make-array Integer/TYPE 2 3))
(pprint a2) => [[0, 0, 0], [0, 0, 0]]
● (def a3 (to-array [1 2 3 4 5]))
(pprint a3) => [1, 2, 3, 4, 5]
Arrays
● Manipulating arrays:
(def a1 (make-array Integer/TYPE 3))
(aset a1 1 10))
(pprint a1) => [0, 10, 0]
(def a2 (make-array Integer/TYPE 2 3))
(aset (aget a2 0) 1 10)
(pprint a2) => [[0, 10, 0], [0, 0, 0]]
Datatypes
● defrecord creates an immutable persistent map (class-type datatype)
(defrecord Hobbit [fname lname address])
(defrecord Address [street town city])
(def bb (Hobbit. "Bilbo" "Baggins" (Address. "Bagshot row" "Hobbiton" "Shire")))
● user=> bb
#user.Hobbit{:fname "Bilbo", :lname "Baggins", :address #user.Address{:street "Bagshot
row", :town "Hobbiton", :city "Shire"}}
● (-> bb :address :city)
“Shire”
Datatypes
● deftype creates a bare-bones object (class-type datatype). Preferred for java
inter operability.
(deftype Hobbit [fname lname address])
(deftype Address [street town city])
(def bb (Hobbit. "Bilbo" "Baggins" (Address. "Bagshot row" "Hobbiton" "Shire")))
● user=> bb
#<Hobbit user.Hobbit@476c6b9c>
● (.street (.address bb))
"Bagshot row"
Protocols
● Dataype are used to implement protocols or interfaces.
(defprotocol Dialogue
(deliver-dialogue [d]))
(defrecord Where? [place]
Dialogue
(deliver-dialogue [d] (str "One does not simply walk into " place)))
● (def LOR (Where?. "Mordor"))
(deliver-dialogue LOR)
=> "One does not simply walk into Mordor"
Thank You :)

More Related Content

Clojure basics

  • 1. Introduction to ClojureIntroduction to Clojure Sidharth Khattri Knoldus Software LLP Sidharth Khattri Knoldus Software LLP
  • 2. ● Clojure is a Functional Lisp (List Processing) which runs on JVM. ● It extends the principle of Code-as-Data system to include Maps and Vectors. Everything in clojure is written inside a data structure referred to as the S-expressions, i.e nested lists. Eg: (/ 4 (+ 1 2)) => ? ● Clojure is a Functional Lisp (List Processing) which runs on JVM. ● It extends the principle of Code-as-Data system to include Maps and Vectors. Everything in clojure is written inside a data structure referred to as the S-expressions, i.e nested lists. Eg: (/ 4 (+ 1 2)) => ? Function Name Arguments ● Every operation in clojure is done using a Post-Fix notation
  • 3. ● Experimenting with clojure is quite easy. In order to get started with clojure you need to follow the instructions on http://leiningen.org/ to set up clojure environment on your system. Leningen is used for project automation. ● Most popular IDE used for clojure is LightTable which can be download from http://www.lighttable.com/ ● You can fire up clojure's repl on linux terminal using: lein repl or you can directly use a Live REPL in LightTable. ● You can also use clojure in Eclipse using CounterClockwise plugin. ● Everything that you need to know about clojure can be found in the clojure cheatsheet at the following url: http://clojure.org/cheatsheet
  • 4. ● Even though a lot of parentheses can confuse programmers at first, LightTable(IDE) can make programming in clojure really easy. A sample of what usage of parentheses I'm talking about: (filter #(if(zero? (rem % 3)) true) (map #(+ % 1) (range 10))) => ? ● The above code in LightTable should look something like this: ● Last line of a function can return another function, i.e a Higher Order Function as illustrated in the following example: (defn attribute [who?] (if (= who? "superman") #(str "Superman " %) (fn[x] (str "Human " x)))) ((attribute "superman") "Flying") => "Superman Flying"
  • 5. (if 0 “Yee! True” “Huh! False”) => ? (if 1 “Yee! True” “Huh! False”) => ? Concept of truthy and falsy
  • 6. (if 0 “Yee! True” “Huh! False”) => “Yee! True” (if 1 “Yee! True” “Huh! False”) => “Yee! True” Concept of truthy and falsy
  • 7. Concept of truthy and falsy Everything in clojure is true except false or nil So, (if nil “Yee! True” “Huh! False”) => “Huh! False”
  • 8. Data Structures ● Clojure supports a number of data structures: Lists, Vectors, Maps, Sets ● All clojure data structures are persistent data structures. Internally they're implemented as a tree. ● Simplest way to define these data structures: '(1 2 3) defines a list [1 2 3] defines a vector #{1 2 3} defines a set {:1 “one” :2 “two”} defines a map
  • 9. Nesting ● Searching and updating nested structures is very easy. ● Searching: (def n {:india {:newdelhi {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}}} :usa {:california {:knoldus {:address "743, Catamaran Street "}}}}) user=> (get-in n [:india :newdelhi]) Returns {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}} ● Updating: (assoc-in n [:india :newdelhi :knoldus :number] 911142316525) Returns {:india {:newdelhi {:knoldus {:number 911142316525, :address "30/29, 1st Floor, East Patel Nagar"}}}, :usa {:california {:knoldus {:address "743, Catamaran Street "}}}} ● Remember that the value of “n” hasn't changed in any case.
  • 10. Threading Operators The previous code that we used: (filter #(if(zero? (rem % 3)) true) (map #(+ % 1) (range 10))) Is same as: (->> (range 10) (map #(+ % 1)) (filter #(if (zero? (rem % 3)) true))) The threaded version is much cleaner
  • 11. Threading Operators In Nested structures example that we used: (def n {:india {:newdelhi {:knoldus {:address "30/29, 1st Floor, East Patel Nagar"}}} :usa {:california {:knoldus {:address "743, Catamaran Street "}}}}) We can use: (-> n :india :newdelhi :knoldus :address) Instead of: (:address (:knoldus (:newdelhi (:india n))))
  • 12. Loops ● For loop: (for [x (range 1 10) :when (even? x)] x) => (2 4 6 8) ● While loop: (while 0 (println “hello”)) ● Loops with side effects: (dotimes [x 5] (print x)) => 01234nil (doseq [x [3 2 1]] (print x)) => 321nil
  • 13. Binding Form - let ● We use the “let” form to bind data structures to symbols. ● Example: (let [x 10 y 11 m (* x y)] m) user=> m
  • 14. Binding Form - let ● We can also use let binding for destructuring: ● (defn index-sum [v & i] (let [[x :as ind] (map #(get v %) i)] (reduce + ind))) (index-sum [1 2 3 4 5 6 7 8 9] 1 3 5) => ?
  • 15. Built-in Parallelism ● “map” function will take more time as compared to the “pmap” function: (time (doall (map (fn[x] (Thread/sleep 3000) (+ x 5)) (range 1 5)))) => "Elapsed time: 12000.99432 msecs" (6 7 8 9) (time (doall (pmap (fn[x] (Thread/sleep 3000) (+ x 5)) (range 1 5)))) => "Elapsed time: 3002.989534 msecs" (6 7 8 9)
  • 16. Futures ● Futures can be used to send any calculation intensive work in the background while continuing with some other work. ● Defining futures: (def f (future some-calculation-intensive-work)) ● Example: (defn show-result[] ;;do things (def f (future some-calculation-intensive-work)) ;;prepare gui to display result @f) ;;wait until the result is returned
  • 17. Atoms, refs and agents ● Atoms, refs and agents are the three options available for maintaining non- local mutable state in clojure ➔ Atoms are for Uncoordinated Synchronous access to a single Identity. ➔ Refs are for Coordinated Synchronous access to Many Identities. ➔ Agents are for Uncoordinated Asynchronous access to a single Identity.
  • 18. Atoms ● Defining an atom: (def a (atom {:a 1})) ● Getting the value stored in an atom: (deref a) or @a ● Changing the value of an atom: (swap! a #(assoc % :b 2)) => {:a 1 :b 2} or (reset! a 0) => Exception or changed value?
  • 19. Refs ● Defining refs: (def tasks-to-be-done (ref #{2 9 4})) (def tasks-done (ref #{1 3 5})) ● Coordinated change: (dosync (commute tasks-to-be-done disj 2) (commute tasks-done conj 2)) ● Accessing values of refs: @tasks-to-be-done => #{4 9} @tasks-to-be-done => #{1 2 3 5}
  • 20. Agents ● Can be useful in fork/join solutions. ● Defining an agent: (def a (agent 0)) ● Dispatching actions to an agent: (dotimes [x 3] (send-off a (fn[x] (Thread/sleep 3000) (inc x)))) @a => ? ● In case we want to wait until the above code snippet has finished processing, we can use: (await a)
  • 21. Arrays ● Defining an array: (def a1 (make-array Integer/TYPE 3)) (pprint a1) => [0, 0, 0] (def a2 (make-array Integer/TYPE 2 3)) (pprint a2) => [[0, 0, 0], [0, 0, 0]] ● (def a3 (to-array [1 2 3 4 5])) (pprint a3) => [1, 2, 3, 4, 5]
  • 22. Arrays ● Manipulating arrays: (def a1 (make-array Integer/TYPE 3)) (aset a1 1 10)) (pprint a1) => [0, 10, 0] (def a2 (make-array Integer/TYPE 2 3)) (aset (aget a2 0) 1 10) (pprint a2) => [[0, 10, 0], [0, 0, 0]]
  • 23. Datatypes ● defrecord creates an immutable persistent map (class-type datatype) (defrecord Hobbit [fname lname address]) (defrecord Address [street town city]) (def bb (Hobbit. "Bilbo" "Baggins" (Address. "Bagshot row" "Hobbiton" "Shire"))) ● user=> bb #user.Hobbit{:fname "Bilbo", :lname "Baggins", :address #user.Address{:street "Bagshot row", :town "Hobbiton", :city "Shire"}} ● (-> bb :address :city) “Shire”
  • 24. Datatypes ● deftype creates a bare-bones object (class-type datatype). Preferred for java inter operability. (deftype Hobbit [fname lname address]) (deftype Address [street town city]) (def bb (Hobbit. "Bilbo" "Baggins" (Address. "Bagshot row" "Hobbiton" "Shire"))) ● user=> bb #<Hobbit user.Hobbit@476c6b9c> ● (.street (.address bb)) "Bagshot row"
  • 25. Protocols ● Dataype are used to implement protocols or interfaces. (defprotocol Dialogue (deliver-dialogue [d])) (defrecord Where? [place] Dialogue (deliver-dialogue [d] (str "One does not simply walk into " place))) ● (def LOR (Where?. "Mordor")) (deliver-dialogue LOR) => "One does not simply walk into Mordor"