Clojure Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Clojure?


Clojure is a dialect of the Lisp Programming Language.


It's a general-purpose and functional programming language.


It's Open Source...


It runs on the JVM, CLR and JavaScript engines.

If you haven't used Lisp or Racket before...Clojure will not come easy

How to install Clojure


Clojure can be installed as a minimal install Clojure

Simply unzip and the run on the terminal


java -cp clojure-1.7.0.jar clojure.main


However...using Leiningen is way better...

Once install...simply run on the terminal


lein repl

Who uses Clojure?


  • Walmart -> Data management system for over 5,000 stores with online and mobile data
  • Beanstalk -> Switch to Clojure to speed up caching by 20x
  • MixRadio -> New services development in Clojure
  • Motorola -> Cellular phone switch testing system
  • Prismatic -> Content analysis and discovery platform
  • Puppet Labs -> TrapperKeeper (and more)

Starting out...


When you run the Lein Repl...

You're going to be able to code Clojure in interactive mode...

Comments


Comments are very simple

				
;This is a commented line...
				

Namespaces are important...to avoid function name conflicts...

				
(ns geekythursday)
				

Parentheses


Parentheses are crucial in Clojure code...


Everything needs to be wrap up in parenthesis...


This might make the code look weird...but that's how it is -:)


Operations


In Clojure, the operator comes first and the parameters follow...


				
(+ 1 2)

3


(- 5 3)

2


(* 8 3)

24


(/ 8 2)

4
				

Variables


Variables will get a type depending on the value they hold...


				
(def myInteger 5)

#'user/myInteger


myInteger

5


(def myString "Hello Clojure!")

#'user/myString


myString

"Hello Clojure!"
				

Unlike other Lisp dialects like Racket, we can change a variables value easily...


				
(def myInteger 5)

#'user/myInteger


myInteger

5


(def myInteger 10)

#'user/myInteger


myInteger

10
				

String are Java objects...


				
(define myString (str "Hello " "Clojure!"))

#'user/myString


"Hello Clojure!"



(class myString)

java.lang.String



(count myString)

14


(.substring myString 6 13)

"Clojure"
				

Lists


Lists are the most common and used variable type in Clojure.


Lists comes with some nice built-in functions...

				
(def myList (list 1 2 3))

#'user/myList


myList

(1 2 3)



(def myList '(1 2 3))

#'user/myList


myList

(1 2 3)
				

We can use "concat" to add values to a list...

				
(def myList (concat myList '(4)))


(1 2 3 4)



(def myList (concat '(5) myList))


(5 1 2 3 4)
				

We can also use "cons" but only to add at the beginning of the list...

				
(def myList (cons 9 myList))


(9 5 1 2 3 4)
				
				
(count myList)

6



(first myList)

9



(last myList)

4



(rest myList 2)

(5 1 2 3 4)



(nth myList 3)

2
				

Functions


Function are very important...that's true for every programming language...


Creating functions is not much different from creating a variable...

				
(defn myFunction[] (println "Hello Clojure!"))

#'user/myFunction



(myFunction)

"Hello Clojure!"

nil
				

Wait a second...can't we get rid of that "nil"?


Sure we can...that nil is just a terminator...so we can easily replace it...

				
(defn myFunction[] (println "Hello Clojure!")

                   (symbol ""))

#'user/myFunction



(myFunction)

"Hello Clojure!"

				

Anonymous Functions


Anonymous Functions allows us to create function without names...like Lambdas in other languages...

				
(#(println "Hello Clojure!"))

"Hello Clojure!"

nil



(def myList '(1 2 3 4))

#'user/myList



(map (fn[x] (* x 2)) myList)

(2 4 6 8)
				

Fibonacci list sequence


Finally...we're going to make our first application...


Name your file "Fibonacci.clj"


				
(ns fibonacci)



(defn fib [num a b]

     (cond 

        (and (> a 0) (> num 1))

             (concat [(+ a b)] 
             
                    (fib (- num 1) (+ a b) a))

        (= a 0)

             (concat (conj (conj [a] b) (+ a b)) 
             
                    (fib (- num 1) (+ a b) b))))



(defn showFib [num]

  (fib num 0 1))
				

When we run it we're going to see...


Making an LCD Number App


This is my favorite application of all time...


Name your file "LED_Numbers.clj"


				
(ns LED_Numbers)



(def leds {"0" (list " _  " "| | " "|_| ") 
	
           "1" (list "  " "| " "| ")

           "2" (list " _  " " _| " "|_  ") 
           
           "3" (list "_  " "_| " "_| ")

           "4" (list "    " "|_| " "  | ") 
           
           "5" (list " _  " "|_  " " _| ")

           "6" (list " _  " "|_  " "|_| ") 
           
           "7" (list "_   " " |  " " |  ")

           "8" (list " _  " "|_| " "|_| ") 
           
           "9" (list " _  " "|_| " " _| ")})
				
				
(defn toList [number]

    (map str(seq(str number))))



(defn get_led [x n num]

    (cond 

        (> (count x) 0)

            (concat (nth (get leds (first x)) n) 
            
                         (get_led (rest x) n num))


        (and (= (count x) 0) (< n 2))

            (concat "" "\n" (get_led (toList num) 
            
                                     (+ 1 n) num))


        (and (= (count x) 0) (= n 2))

            (concat "" "\n")))         
				
				
(defn showLED [num]

    (print (apply str 
    
                  (get_led (toList num) 0 num)))
                    
                           (symbol ""))
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays


We will measure the runtime


Name your file "Random_Names.clj"


				
(ns Random_Names)


(def names '["Anne" "Gigi" "Blag" "Juergen" "Marek" 

             "Ingo" "Lars" "Julia" "Danielle" "Rocky" 
             
             "Julien" "Uwe" "Myles" "Mike" "Steven" 
             
             "Fanny"])
             
             
             
(def last_names '["Hardy" "Read" "Tejada" "Schmerder" 

                  "Kowalkiewicz" "Sauerzapf"  "Karg" 
                  
                  "Satsuta" "Keene" "Ongkowidjojo" 
                  
                  "Vayssiere" "Kylau" 
                  
                  "Fenlon" "Flynn" "Taylor" "Tan"])             
				
				
(defn generate_names[]

     (concat (cons (nth names (rand-int 16)) '())
     
             (cons (nth last_names (rand-int 16)) '())
             
     ))
    
             

(defn show_names[]
	
	(time (loop [i 0]
	
		(when (< i 100000)
	
			(generate_names)
	
			(recur (inc i))))))
				

When we run it we're going to see...


Time is measured in milliseconds...so that's about 0.074 seconds...

That's pretty fast...

Comparing it with Julia and Python...

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "Decimal_to_Roman.clj"


				
(ns Decimal_To_Roman)



(def Romans (sorted-map-by > 1000 "M", 900 "CM", 

                              500 "D", 400 "CD", 
                              
                              100 "C", 90 "XC",
                              
                              50 "L", 40 "XL", 
                              
                              10 "X", 9 "IX", 
                              
                              5 "V", 4 "IV", 1 "I"))
				
				
(defn Get_Romans [num Romans]

    (let [roman (first(first Romans))]

        (cond

            (>= num roman)

                (apply str(concat 
                
                          (second (first Romans)) 
                          
                          (Get_Romans (- num roman) 
                          
                          Romans)))

            (and (< num roman) (> num 0))

               (Get_Romans num (rest Romans))

        )))
        
        
        
(defn Show_Romans [num]

    (println (Get_Romans num Romans))(symbol ""))
				

When we run it we're going to see...


Counting Letters


In this example we're going to read a file and count how many time a letter appears...


Call your file "countletters.clj" (all in lowercase).


Create a file called "readme.txt" with the following text...


"This is a text file that we're going to read it using Clojure"


				
(ns countletters)



(def text (seq (slurp "readme.txt")))



(defn dict-inc [m word]

  (update-in m [word] (fnil inc 0)))



(defn CountLetters[]

	(reduce dict-inc {} text))
				

When we run it we're going to see...


That's it for now...


I hope you had some fun...


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...