Skip to content

Instantly share code, notes, and snippets.

@hindol
Last active August 8, 2021 15:51
Show Gist options
  • Save hindol/727eb69e9943b371e66902c19960fd0c to your computer and use it in GitHub Desktop.
Save hindol/727eb69e9943b371e66902c19960fd0c to your computer and use it in GitHub Desktop.
Clojure in 15 Minutes: A Crash-course

Clojure in 15 Minutes

Hello, Clojure!

(println "Hello, world!")
  • The same in Python,
    print('Hello, world!')
  • ( comes before the function, not after.
  • (x y z) => Call function x with two arguments, y and z.

Arithmetic

(+ 1 2 3 4 5)  ;; => 15
(- 10 4 3 2)   ;; => 1
(- 1)          ;; => -1
(* 1 2 3 4 5)  ;; => 120
(/ 6 3 2)      ;; => 1
(/ 10)         ;; => 1/10
(float (/ 10)) ;; => 0.1
  • Arithmetic operators in Clojure support more than two operands.
  • (f (g x)) => Call function g with argument x. Then call function f with the result of the previous function as argument.

Vectors & Sets

[1 "two" 3.0]         ;; => A vector
(nth [1 "two" 3.0] 2) ;; => 3.0

#{1 "two" 3.0}                 ;; => A set
(contains? #{1 "two" 3.0} 2.0) ;; => false
(#{1 "two" 3.0} 2.0)           ;; => false
  • Collections in Clojure are not typed. Much like Python.
  • Functions that return true/false usually end in a ?. However, this is not enforced.
  • A set is also a function(!)

Maps

{:one 1 :two 2.0 :three "three"}        ;; A map
(:one {:one 1 :two 2.0 :three "three"}) ;; => 1
  • Symbols starting with : are keywords. Think enums or named strings. Keywords are primarily used as map keys.
  • Keywords are also functions(!)

Symbols

(def x 10)
  • x is a symbol.
  • 10 is a value.
  • def binds a symbol to a value.

Functions

(fn [x] (* x x))     ;; A function without a name
((fn [x] (* x x)) 2) ;; => 4
  • ((fn [x] (* x x)) 2) => Call function (fn [x] (* x x)) with the argument 2.

Give that Function a Name

(def square (fn [x] (* x x))) ;; Bind the symbol "square" to a function
(square 2)                    ;; => 4

Macros

(defn square [x] (* x x))
  • This gets re-written as (def square (fn [x] (* x x))) before evaluation.
  • Think #define in C/C++ but macros are much more powerful.
(-> x        ;; The thread-first macro
    (square)
    (cube))
  • This gets re-written as (cube (square x)) before evaluation.
  • The thread-first macro (->) threads the previous result as the first parameter of the next function.
  • Similarly, the thead-last macro (->>) threads the previous result as the last parameter of the next function.

The Essence of a Functional Language, Pure Functions

Definition: A function that has no side-effects. Calling the function any number of times with the same input value will give the same output value.

  • In the above example, square is a pure function. No matter how many times you call it with the value 2, the output will be 4.
  • A function that debits money from a bank account is not a pure function.
  • Printing to the console is a side-effect. It changes the state of stdout. So is writing to a file.
  • Clojure is built around pure functions.

Example

(def a-vector [1 "two" 3.0])
(conj a-vector :four)        ;; [1 "two" 3.0 :four]
a-vector                     ;; [1 "two" 3.0]
  • conj(oin) takes a vector, adds an entry at the end and returns another vector. The original vector is not modified.
(def a-map {:one 1 :two 2 :three 3})
(assoc a-map :four 4)                ;; => {:one 1 :two 2 :three 3 :four 4}
a-map                                ;; => {:one 1 :two 2 :three 3}
  • assoc(iate) takes a map, adds an entry and returns another map. The original map is not modified.

Map, Filter & Reduce

(defn root-mean-square
  [xs]                             ;; A sequence in Clojure is usually named xs, ys etc.
  (let [n       (count xs)
        squares (map square xs)    ;; => (1 4 9)
        sum     (reduce + squares) ;; => 14
        mean    (/ sum n)]         ;; => 4.666666666666667
    (Math/sqrt mean))              ;; => 2.160246899469287

(root-mean-square [1 2 3])         ;; Results at each step shown above.
  • (Math/sqrt mean) => Calls Java Math.sqrt. Clojure runs on the JVM and has access to the complete Java ecosystem.
  • reduce reduces a collection to a single value.
(filter odd? [1 2 3 4 5 6 7 8 9 10]) ;; => [1 3 5 7 9]

If & When

(if   true  "true" "false") ;; => "true"
(when false "true")         ;; => nil
  • Use if when there is also an else part.
  • Use when otherwise.
  • nil is what null is in other languages or None in Python.

Cond

(cond
  (odd?  x) "x is odd"
  (even? x) "x is even")
  • cond is what switch/case is in other languages.

Local Bindings

(let [x 10]
  (println "x is: " x)) ;; => x is: 10

(println "x is: " x)    ;; Unable to resolve symbol: x in this context
  • Like def but the binding is only available within the form (let ...).

Loop & Recur

(defn factorial
  [x]
  (loop [n   x                  ;; "n" is locally bound to "x"
         acc 1]
    (if (> n 1)
      (recur (dec n) (* acc n)) ; Re-run the "loop" with new arguments.
      acc)))                    ; The current stack is replaced with the
                                ; new stack, so no stack overflow.
  • (> n 1) => n > 1 in other languages.
  • (< 0 x 11) => Check if x is between 0 and 11 (both exclusive).
  • (= x y z) => Check that x, y and z are all equal.
  • Most operators in Clojure allow more than two operands.
@samuelkarani
Copy link

thanks man!!

@hindol
Copy link
Author

hindol commented Apr 10, 2020

@samuelkarani You are welcome. Are you learning Clojure?

If you are, then as next steps, I recommend solving the Clojure Koans (not mine). It's an awesome resource.

@lov3catch
Copy link

thx :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment