Clojure made easy

Interactive Slides

chart?cht=qr& clojure

Yehonathan Sharvit

	(str (js/Date.))

Who am I?

  • A pragmatic theorist

  • A freak of interactivity

  • Author of Klipse: a client side code evaluator pluggable on any web page

  • Running a small consulting company

  • Sparking the joy of Clojure at Cycognito, Audyx and Nextjournal


Yehonathan Sharvit @viebel

Begin with the End in Mind

  1. You are motivated to learn Clojure

  2. You look differently at your existing Software knowledge

  3. You feel you had a fun time

You want to read my book on Clojure 馃捀


Three+One wishes

  1. I wish I could express myself clearly

  2. I wish I could code in a simple way

  3. I wish I could write (and read) code that is predictable

  4. I wish I could get more wishes


Power of expressions

express yourself

The lack of power of expressions

We cannot assign the result of an if or a switch statement to a variable.

var a = if (true) { 5 } else {42};

We cannot comment out an expression.

function foo() {
 // if (true) {
 //   return 5;
 // } else {
 //   return 42;
 // }
  return 7;

The syntax is not uniform: operator, statements, function calls, function definition, classes…​

function foo(z) {
return z + Math.sqrt(z);

The power of expressions

Every part of the language is an expression, with the same structure

arithmetic operation

(+ 1 2)

boolean operation

(and true false)

local bindings

(let [a 42]
  (+ a 5))

variable assignment

(def my-num 42)

if expression

(if my-num "happy" "sad")

function call

(inc 42)

The power of expressions - Javascript vs. Clojure



foo(1, 2)
(foo 1 2)
2 + 3
(+ 2 3)
if (x > 2) {
  return 3;
} else {
  return 5;
(if (> x 2)
var myNum = 42
(def my-num 42)

The power of expressions - the rules

  1. An expression is enclosed into opening and closing parenthesis: (), [] or {}

  2. First element inside the parentheses is the name of the expression: def, if, +…​

  3. Other elements inside the parentheses are the arguments to be passed to the expression, either a primitive or an expression

  4. When one of the arguments is itself an expression, it follows the same syntactic rules (recursively)

(defn foo [x y]
  (if (= x (+ y y))
    (* x y)
    (inc x)))
(foo 42 20)

The power of expressions - if expressions

We can assign the result of an if expression into a variable

(def my-mood (if my-num "happy" "sad"))

The power of expressions - comments

We can comment out a single expression out of a big piece of code

(defn print-moods [num]
  (println "happy")
  #_(if (= num 42)
    (println "furious")
    (println "angry"))
  (println "sad"))

(print-moods 42)

The power of expressions - macros

We can write code that receives source code and genenerates another code.

Pure functions are helpful

Challenge 1

Write a function that receives a name and prints to the console
Hello <name>!

You may use the language of your choice.

Hello Javascript

function hello(name) {
console.log(`Hello, ${name}!`);

Thoughts 馃

  1. Can you write a unit test?

  2. Can you compose?

  3. Can you cache?

Hello Clojure

We are going to separate:

  • Computation (concatenation of "Hello" and name)

  • Side effects (print to the console)

Hello Clojure

We create a function named hello-str that receives name
and "computes" the concatenation of "Hello" and name

(defn hello-str [name]
  (str "Hello, " name "!"))

The hello function that does the side effect (print) uses hello-str:

(defn hello [name]
  (println (hello-str name)))
(hello "Clojure")

Pure functions vs. side effects

A pure function


A function with side effects


Key idea: separate side effects from computation

print hello

The value of pure functions

  1. Testable

  2. Composable

  3. Cachable


A trivial test case

(deftest test-hello-clojure
   (is (= (hello-str "Clojure")
          "Hello, Clojure!")))



馃 Can you test the function you wrote to solve the challenge?


We can use our functions as building blocks 馃П for other functions.

We compose as we wish

(defn hello-cap [name]
  (upper-case (hello-str name)))

It returns a composed string

(hello-cap "Clojure")

We print it, later

(println (hello-cap "Clojure"))

馃 Can you compose the function you wrote without modifying its code?

Hello worlds

Handle sequences

Let’s handle sequence of names

(map hello-str ["Clojure" "Python" "Javascript" "Java"])

Let’s combine the elements of the sequence, into a string

(defn multiple-hellos [names]
  (join " " (map hello names)))

We print, later

(println (multiple-hellos ["Clojure" "Python" "Javascript" "Java"]))


Imagine that string concatenation were a heavy operation.

(defn hello-print [name]
  (println (str "Hello, " name "!")))

We would like to cache the function
Next time we call it, it returns the result immediately

馃お It makes no sense to cache a function with side effects!

(def memoized-print (memoize println))
(memoized-print "Hello!")
(memoized-print "Hello!")
(memoized-print "Good bye!")

Interlude: A brief history of Functional Programming


1930: Lambda Calculus

  • Alonzo Church discovers the 位-calculus

  • Everything is an anonymous function with a single argument

  • No names in the language - only function argument

  • Even numbers are expressed as functions

    • 0 := 位f位x.x

    • 1 := 位f位x.fx

    • 2 := 位f位x.f(fx)

1958: LISP

  • John McCarthy invents LISP

  • It is the 1st FP language

  • The data is expressed as S-Expressions: (1 2 3), (a b (c d)) etc…​

  • The code is made of S-Expressions: (+ 1 2 3), (if true 1 42) etc…​

1995: Javascript the language of the browser

  • Brendan Eich is recruited by Netscape to do "scheme in the browser"

  • Eventually, he invents Javascript

  • Functions are 1st class citizens

  • JSON data format is similar to S-Expressions

2000s: Clojure

  • 2007 - Rich Hickey invents Clojure - A practical dialect of LISP on top of JVM

  • 2011 - ClojureScript - Clojure rocks, Javascript Reaches!

  • 2013 - Facebook creates react.js - A functional javascript frontend framework

  • 2015 - Dan Abramov invents redux - A javascript library that imposes FP constraints on a frontend app

Dealing with Data is valuable

time money

The value of values

Challenge 2

Read carefuly the following piece of code and tell me what is the value of x?

You may convert the code to the language of your choice.

const x = 42;

The value of values

Challenge 3

Read carefuly the following piece of code and tell me what is the value of y?

You may convert the code to the language of your choice.

const arr = [5, 99, 1230];
const z = calcVeryUseful(arr);
const y = arr.length;

Welcome immutability


What is immutability?

Immutability means that data collections are treated like values.
Values never change!

In the realm of numbers

(def my-num 42)
(inc my-num)

In the realm of strings

(def my-str "Hello")
(str my-str " Clojure!")

In the realm of vectors

(def my-vec [42 400 532])
(assoc my-vec 1 54)

In the realm of maps

(def my-map {:name "Franck"})
(assoc my-map :metadata 12321321)

The value of immutability

  1. Code is predictable

  2. No "by reference" or "by value" headache

  3. Equality check is fast

  4. Concurrency friendly wihtout locks

Beyond immutability



(def my-state (atom {}))
(swap! my-state assoc :money 1000)


Extend the language with macros

  1. It would be cool to write asynchronous code that looks synchronous

  2. It would be fun to add debugging capabilities

  3. It would be productive to write code that disappears on production

  4. It would be nice to pass data to data manipulation functions sequentially

Custom debugging

(defn complex-stuff [x & forms]
  (loop [x x forms forms]
    (if forms
      (let [form (dbg (first forms))
            threaded (list (first form) (first (next form)) x)]
        (recur threaded (next forms)))

(complex-stuff 10 [1 2] [4 5])

Pipeline instead of wrapping

Wrapping functions become hard to read

(reduce +
        (filter odd?
                (map inc (range 100))))

Use pipelines

                (range 100)
                (map inc )
                (filter odd? )
                (reduce + ))

It’s a macro

(macroexpand '(->>
                (range 100)
                (map inc)
                (filter odd?)
                (reduce +)))

Macros Internals


Macros Internals

(defn transform [x & forms]
  (loop [x x forms forms]
    (if forms
      (let [form (first forms)
            threaded (list (first form) (first (next form)) x)]
        (recur threaded (next forms)))
(transform '(range 100)
           '(map inc)
           '(filter odd?)
           '(reduce +))

Wishes come true

  1. I wish I could express myself clearly
    The power of expressions

  2. I wish I could code in a simple way
    Pure functions

  3. I wish I could write (and read) code that is predictable

  4. I wish I could get more wishes