Clojure

Functional Programming

in LISP

on the JVM

LISP?

(((((((((((((???)))))))))))))

Yes, Clojure has parentheses

Minimal syntax

1
2
3
4
5
6
7
8
9
10
(some-function arg-one arg-two)

; data structures
(def list '(1 2))
(def vector [1 2 3])
(def map {:a 1})
(def set #{:a :b})

; anonymous functions
(map #(* % %) vector)

Hello world!

The kingdom of nouns

1
Greeter.greet("Lambda Lounge")
1
2
3
4
5
module Greeter
  def self.greet(name)
    puts "Hello, #{name}"
  end
end

The kingdom of verbs

1
(greet "Lambda Lounge")
1
2
(defn greet [name]
  (println "Hello," name))

Polymorphism

1
2
3
user.render(canvas)
monster.render(canvas)
tree.render(canvas)
1
2
3
(render user canvas)
(render monster canvas)
(render tree canvas)
1
2
3
4
5
(defn render [object canvas]
  (case (:type object)
    :user (render-user object canvas)
    :tree (render-tree object canvas)
    :monster (render-monster object canvas)))

Protocols

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(defprotocol Renderable
  (render [object canvas]))

(defrecord User [...]
  Renderable
  (render [user canvas] ...)

  ; same name, different protocol
  ConsoleRenderable
  (render [user] ...))

(extend-type String
  Renderable
  (render [s canvas] ...))

(defn make-renderable [foo]
  (reify
    Renderable
    (render [_ canvas] ...)))
1
2
3
4
spaceship.collide(other_spaceship)
spaceship.collide(rock)
rock.collide(rock)
rock.collide(spaceship)
1
2
3
4
(collide spaceship other-spaceship)
(collide spaceship rock)
(collide rock rock)
(collide rock spaceship)
1
2
3
4
5
6
7
8
9
10
11
(defmulti collide (fn [& args] (map :type args)))

(defmethod collide [::spaceship ::spaceship]
  [spaceship-one spaceship-two]
  ...)

(defmethod collide [::spaceship ::immobile]
  [spaceship-one immobile]
  ...)

(derive ::rock ::immobile)

Polymorphism is not just for OO

Boilerplate

1
2
3
4
5
6
7
8
9
begin
  transaction = Transaction.new
  do_some_stuff
  transaction.commit
rescue => e
  Logger.error("Transaction failed")
  transaction.rollback
  raise
end
1
2
3
with_transaction do
  do_some_stuff
end
1
2
3
4
5
6
7
8
9
10
(try
  (let [transaction (open-transaction)]
    (do
      (save-user user)
      (save-order order))
    (commit transaction)
    (catch Exception e
      (log "Transaction failed")
      (rollback transaction)
      (throw e))))
1
2
3
(with-transaction
  (save-user user)
  (save-order order))
1
2
3
4
5
6
7
8
9
(defn do-with-transaction [block]
  (try
    (let [transaction (open-transaction)]
      (block) ; <-- changed
      (commit transaction)
      (catch Exception e
        (log "Transaction failed")
        (rollback transaction)
        (throw e)))))
1
2
3
4
(do-with-transaction
  #(do
    (save-user user)
    (save-order order)))
1
2
3
(defmacro with-transaction [body]
  `(do-with-transaction
    (fn [] (do ~@body))))
1
2
3
(with-transaction
  (save-user user)
  (save-order order))
1
2
3
4
5
if !condition
  do_unless_condition
else
  do_if_condition
end
1
2
3
4
5
6
# ???
if_not condition
  do_unless_condition
else
  do_if_condition
end
1
2
3
4
5
6
7
8
9
if_not condition do
  self.then do
    do_unless_condition
  end

  self.else do
    do_if_condition
  end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class IfNot
  def then(&block)
    @then = block
  end

  def else(&block)
    @else = block
  end

  def run(condition)
    if !condition
      @then.call if @then
    else
      @else.call if @else
    end
  end
end

def if_not(condition, &block)
  runner = IfNot.new
  runner.instance_eval(&block)
  runner.run(condition)
end
1
2
3
(if-not condition
  (do-unless-condition)
  (do-if-condition))
1
2
3
4
(defmacro if-not [condition do-unless do-if]
  `(if (not ~condition)
      ~do-unless
      ~do-if))

The small print

1
cant_touch_this if clojure?
1
2
3
4
5
; this won't work
(cant-touch-this if ruby?)

; that's the closest you can get
(? cant-touch-this if ruby?)

Add any feature as long as it looks like LISP

The
understated elegance
of LISP

Code is Data

1
2
(defn greet [name]
  (println "Hello," name))

Functional Programming

Moore's law

The ingredients

First order functions

1
2
3
4
5
6
7
8
(def add-5 (partial + 5))
(def times-3 (partial * 3))

(map (comp add-5 times-3) (range 10))
;=> (5 8 11 14 17 20 23 26 29 32)

(map (juxt add-5 times-3) (range 10))
;=> ([5 0] [6 3] [7 6] [8 9] [9 12] ...)

Compared to OO

smaller units of composition

lower coupling

1
2
3
4
5
def index(policy, user)
  if policy.is_authorized?(user)
    do_something
  end
end
1
2
3
(defn index [is-authorized? user]
  (if (is-authorized? user)
    (do-something)))

Laziness

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
; infinite sequence of prime numbers
(def prime-numbers (filter prime? (range)))

(take 10 prime-numbers)

(reduce +
  (take 10
    (filter palindrome? prime-numbers)))

; again with the macros...
(->>
  prime-numbers
  (filter palindrome?)
  (take 10)
  (reduce +))

Immutability

1
2
3
4
5
6
7
8
9
(def foo [1 2 3])

(def bar (conj foo 4))

(prn x)
;=> [1 2 3]

(prn y)
;=> [1 2 3 4]

How about this?

1
2
3
4
5
; a few Gb of RAM
(def foo (take 1000000000 prime-numbers))

(def bar (conj foo 4))
(def baz (conj bar 5))

Persistent data structures

Immutability enables concurrency

Immutability enables abstraction

What does this code do?

1
notification_builder.build(events)
1
(build-notifications events)

FP is about
handling state
not passing around functions

Functional core,
Imperative shell

1
2
3
4
5
6
7
8
9
10
11
(let [
  ; get the necessary data from the database
  user (find-user user-id)
  orders (orders-for-user user-id)

  ; figure out how the world should change
  tax-policy (make-tax-policy (:country user))
  invoice (build-invoice tax-policy user orders)]

  ; interact with the outside world
  (send-invoice (:email user) invoice))

Same approach to concurrency

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(def game (atom (make-game)))

; clients (many threads)
(loop
  (do
    (swap! game process-input (read-input))
    (->>
      @game
      render
      (send client-socket)))

; server (one thread)
(loop
  (do
    (swap! game handle-collisions)
    (swap! game respawn-npcs)))
1
2
3
4
5
6
7
8
; pure functions (all return a new game)
(defn make-game [] ...)
(defn process-input [game input] ...)
(defn handle-collisions [game] ...)
(defn respawn-npcs [game] ...)

; also pure, returns bytes to send
(defn render [game] ...)

Separation of value/state/identity

1
2
3
4
5
6
7
8
9
; value
{:name "Clojure" :awesome true}

; state = value at a point in time
@current-language
=> {:name "Clojure" :awesome true}

; identity
(def current-language (atom clojure))

Moar concurrency!

1
2
3
4
5
6
7
8
(def bob (ref (make-player)))
(def alice (ref (make-player)))

; do in transaction
(dosync
  (if (> (:stars @bob) (:stars @alice))
    (alter alice give-moar-stars)
    (alter bob give-moar-stars)))
1
2
3
4
5
6
; fires off immediately
(def the-answer-to-life
  (future (Thread/sleep 10000) 42))

; blocks until future result is calculated
@the-answer-to-life
1
2
3
4
5
6
7
8
9
(def promised-land (promise))

; will block until delivered
@promised-land

; can check if realized
(realized? promised-land)

(deliver promised-land :far-far-away)
1
2
3
4
5
6
7
(def counter (agent 0))

; asynchronous
(send counter inc)

; get current agent value
@counter
1
2
3
4
5
6
7
8
9
10
(def ^:dynamic x 0)
(def ^:dynamic y 0)

; the values of x and y are changed
; but only within the context of the
; current thread and within the
; (binding) call
(binding [x (inc x)
          y (inc y)]
  (do-something))

JVM language

Bonus: ClojureScript

one language everywhere?

Clojure

Changes the way you think

General-purpose

Function: smaller unit of reuse

No inheritance :)

Logic is separated into pure functions and changing state

Expressive

Dynamic typing

Shoot yourself in the leg (if you want to)

Build your own language language

Extensive data manipulation library

Some learning resources

Programming Clojure

Joy of Clojure

Clojure Programming

Functional Programming for Object-Oriented Programmer

ClojureScript Up and Running

4clojure.com

@apohorecki
github.com/psyho

Thank you