6. Rationale and Philosophy
● First released by Rich Hickey in 2007
○ Expressive functional programming with Lisp
○ Designed for concurrency use by default
○ Embedded in an existing platform
● Robust, practical, high-performance
● Simple abstractions backed by powerful
ideas
7. The familiar solutions are complex
● Complacency breeds incidental complexity
○ Large programs are difficult to understand
○ Scope of effects are difficult to reason about
○ Concurrency: holy crap.
● “Object-oriented programming is overrated”
8. Clojure is a Lisp
About the use of language: it is
impossible to sharpen a pencil with a
blunt axe. It is equally vain to try to do it
with ten blunt axes instead.
- Edsger Dijkstra
How do we tell truths that might hurt?, EWD498
(Actually John McCarthy.)
9. Clojure is a Lisp
● LISP: code=data, few primitives, abstraction
○ Local maximum in the hierarchy of expression
● Dynamically typed and compiled, interpreted
● Syntactic abstraction through macros
● Clojure:
○ Extends code-as-data to new data structures
○ Modernizes LISP with new ideas from existing
functional languages
10. Clojure is Functional and Dynamic
● Functions are first-class
● All data structures are immutable, persistent,
recursive, and support heterogeneous types
● Well-defined concurrent behavior
● Strict typing (i.e., Haskell, OCaml) is not
everyone nor needed for every application
11. Clojure Runs on the JVM (and Javascript!)
● OS independent
● JVM: Well-supported, existing platform, lots
of libraries/platforms
● Static types and safety
● Garbage collection and a great compiler
● Clojurescript:
○ Javascript as the platform: runs everywhere
22. Expressions are Data
(op ...)
● op can be a ….
○
○
○
○
○
Function: +, mod, println
Macro: when, cond, and
Special Operator: do, if, ref
Higher-order function
… anything callable (clojure.lang.IFn)
23. Function calls use parens...
user=> (defn hello [] "Hi!!!") ;; define hello function
user=> hello
;; return it
#<user$hello user$hello@be1a6e>
user=> (hello)
;; invoke it
"Hi!!!"
… but values never do
user=> (def my-name "Kelly Q. Programmer")
#'user/my-name
user=> my-name
"Kelly Q. Programmer"
user=>(my-name)
ClassCastException java.lang.String cannot be cast to clojure.
lang.IFn
24. Quote makes “variables” symbolic
user=> (def x 3)
#'user/x
user=> (+ x 2)
5
user=> '(+ x 2)
(+ x 2)
;; quoted list
;; returns list, unevaluated
user=> (quote (+ x 2))
(+ x 2)
;; same as above
25. Introspect your Environments
user=> (use 'clojure.repl) ;; Quoted symbol
user=> (doc if)
;; Print docstring
------------------------if
(if test then else?)
Special Form
Evaluates test. If not the singular values nil or false,
evaluates and yields then, otherwise, evaluates and yields
else. If
else is not supplied it defaults to nil.
Please see http://clojure.org/special_forms#if
nil
26. Introspect your Environments
user=> (source when)
(defmacro when
"Evaluates test. If logical true, evaluates body in an
implicit do."
{:added "1.0"}
[test & body]
(list 'if test (cons 'do body)))
nil
For More:
●
find-doc - Print docstring for var whose doc or name matches a pattern
●
apropos - returns a seq of definitions matching a regex
●
pst - print stack trace for a given exception or *e by default
●
See: http://clojure.org/cheatsheet
27. Namespaces are all around you
● Namespaces disambiguate names
○
vars -> symbols, functions, macros, Java class etc.
are all defined in namespaces
● Namespace management is a big part of
Clojure development
(ns com.your.great.app
(:require clojure.string
[clojure.set :as set]
[clojure.java.io :refer (file reader)]))
29. Functional Abstractions are Useful
● Clojure is functional
● Functions and higher-order functions are
generic in a obviously fundamental ways
● clojure.core (mostly) free of side-effects
● TBDL: Immutability and persistence
guarantee behavior and performance
30. defn binds functions
(defn messenger
;;
([]
;;
(messenger "Hi!"))
;;
([msg]
;;
(println msg))
;;
([msg & args]
;;
(println msg args)))
;;
user=> (messenger)
Hi!
user=> (messenger "Hi class!")
Hi class!
user=> (messenger "Hi class!" "Who?"
Hello class! (Who? What?)
multi-arity definition
no args
call self with default
one arg
print it
variadic definition
apply print to all args
"What?")
32. apply applies functions
● Invokes argument on arguments (last is a
sequence).
;; & puts rest of args into sequence
;; apply pulls args out of sequence
(defn messenger [greeting & who]
(apply println greeting who))
user=> (messenger "Hi, everyone!" "Who?" "What?")
Hi, everyone! Who? What?
33. let binds symbols to values
● Values are either literal or expressions
● Bound symbols have “lexical scope”
(defn messenger [msg]
(let [a “Who?”
b “What?”
c (capitalize msg)]
(println a b c)))
user=> (messenger “Why?”)
Who? What? Why?
34. Closures
● Allows bindings to persist beyond the lexical
scope
(defn messenger-builder [greeting]
(fn [who] (println greeting who)))
;; defines closure
;; greeting provided here, then goes out of scope
(def hello-er (messenger-builder "Hello"))
;; greeting still available because hello-er is closure
user=> (hello-er "world!")
Hello world!
36. Expressions in Clojure
● Java, etc. : Expressions
return values, but
statements do not.
● Clojure: Everything is an
expression (-> value or
nil)
String s;
(if (= s “foo”) “bar”)
if (s == “foo”) {
s = “bar”;
}
return s;
(do (stuff)
;; Do stuff.
(= s “foo”) ;; => true
37. Flow Control Operators
● if, when, if-not, when-not, do, cond,
case, etc. are all flow control operators.
● composable and general
39. if, do, and when
user => (if (even? 5)
;; if is multibranch
(do (println "Even!") ;; do evaluates block and
true)
;; returns last value
(do (println "Odd!")
false))
odd
;; printed
false
;; return value
user => (when (even? 5)
(println "Even!")
true)
;; when is single-branch
;; sugar for (if <>(do..))
40. cond and case
(let [x 22]
;; Compares predicates
(cond
(<= x 22) "Dismissed as coincidence."
(> x 222) "x is greater than 222."
:else
"No conditions met"))
(defn bazbar [x]
(case x
22 "x is 22"
222 "x is 222"
"x is neither 22 or 222"))
;; Matches arguments
;; in O(1) time
;; Must be literals
42. Threading Macros Remove Nesting
;; Deeply-nested parens ...
(first (.split (.replace (.toUpperCase "a b c d") "A" "X")
" "))
;; ...
are unwinded with thread-first macro
(-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first)
;; Also ->>, as->, cond->, cond->>, etc.
43. Recursion (with loop/recur)
● loop binds, recur re-loops
● Strong prefer iteration and higher-order
functions over recursion
(loop [i 0]
(if (< i 22)
(recur (inc i))
i))
22
45. Collections
● Extensive facilities for representing and
manipulating data
● Small number of data structures
● Seq abstraction common across data
structures
● Large library of functions across all of them
46. Collections: Immutability
● Simple (numbers, strings) and compound
values are immutable
● Key to Clojure's concurrency model
● Cannot change immutable values
○ Generate new ones instead
○ Persistent data structures for efficiency
47. Collections: Persistent Data
Structures
● New values = old values + modifications
● New values are not full copies
● New value and old value are both available
after 'changes'
● Performance guarantees for most operations
● All Clojure data structures are persistent
50. Collections: Data Structures
● Sequential: list
○
○
○
○
Singly-linked lists
Prepend: O(1)
Lookup: O(1) at head, O(n) anywhere else
Grow at the head (front)
51. Collections: Data Structures
● Sequential: list
()
;=> the empty list
(:a :b :c)
; error because :a not function
'(:a :b :c)
;=> (:a :b :c)
(list :a :b :c)
;=> (:a :b :c)
(conj '(:b :c) :a) ;=> (:a :b :c)
63. Collections: Data Structures
● Sequential: list, vector
● Associative: map, set
○
○
○
○
Set of distinct values
Insert: O(1) *
Member?: O(1) *
Unordered
64. Collections: Data Structures
● Sequential: list, vector
● Associative: map, set
#{}
#{"a" "b"}
;;=> the empty set
;;=> #{"a" "b"}
(set ["a" "b"])
;;=> #{"a" "b"}
(conj #{} "a")
;;=> #{"a"}
(contains? #{"a"} "a") ;;=> true
65. Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b"
66. Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b"
● Keywords are functions of maps
(:b dict)
;;=> "b"
67. Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b"
● Keywords are functions of maps
(:b dict)
;;=> "b"
● Sets are functions of their elements
(def s #{3 7 9})
(s 7)
;;=> 7
68. Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b) ;;=> "b"
● Keywords are functions of maps
(:b dict)
;;=> "b"
● Sets are functions of their elements
(def s #{3 7 9})
(s 7)
;;=> 7
● Vectors are functions of their indices
(def v [:a :b :c])
(v 1)
;;=> :b
69. Collections: Destructuring
● Declarative way to pull apart compound data
○ vs. explicit, verbose access
● Sequential & associative data structures
● Nests for deep, arbitrary access
● Works in fn and defn params, let bindings
73. Sequences
● Abstraction for representing iteration
● Backed by a data structure or a function
○ Can be lazy and/or "infinite"
● Foundation for large library of functions
74. Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil
75. Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil
● (first coll) returns the first element
76. Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil
● (first coll) returns the first element
● (rest coll) returns a sequence of the rest of
the elements
77. Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil
● (first coll) returns the first element
● (rest coll) returns a sequence of the rest of
the elements
● (cons x coll) returns a new sequence: first is
x, rest is coll
78. Sequences: Example
(seq [1 2 3])
;=> (1 2 3) ; not a list
(seq "Clojure")
;=> (C l o j u r e)
(seq {:a 1 :b 2})
;=> ([:a 1] [:b 2]) ; seq of map entries
(seq a-java-array) ;=> (...)
(seq [])
(seq "")
(seq {})
;=> nil
;=> nil
;=> nil
80. Sequences: Over Structures
● We can treat any data structure as a seq
(def s '(1 2 3))
(def a (first s))
; s is a list
; a is 1
s
a
1
2
3
81. Sequences: Over Structures
● We can treat any data structure as a seq
(def s '(1 2 3)) ; s is a list
(def r (rest s)) ; r is a seq
s
r
1
2
3
82. Sequences: Over Structures
● We can treat any data structure as a seq
(def s '(1 2 3))
; s is a list
(def b (first (rest s)) ; b is 2
(def b (second s))
; same thing
s
1
b
2
3
83. Sequences: Over Structures
● We can treat any data structure as a seq
○ Lists are seqs
○ Others are wrapped
○ Associative structures become sequence of pairs
84. Sequences: Over Functions
● Can map a generator function to a seq
● Seq is lazy, can be infinite
● Can process more than fits in memory
(def
(def
(def
(def
(def
(def
(def
r (range 1 100))
; r is a lazy seq
a (first r))
; a is 1
s (rest r))
; s is a lazy seq
b (first (rest r))
; b is 2
b (second r))
; same thing
c (first (rest (rest r)))) ; c is 3
c (nth r 2))
; same thing
90. Sequences: reduce
(reduce function init seq)
●
●
●
●
function takes 2 arguments: accumulator and the current argument
reduce calls (function init (first seq))
Return value becomes init for next step
Repeat until the end of the seq, returns the last init
(reduce (fn [total item] (+ total (* 10 item)))
0 ; init
[1 2 3 4]) ;=> 100
92. Combine sequence functions: Power
;; Sum of the first 50 odd integers
(reduce + (take 50 (filter odd? (range)))) ;=> 2500
;; Top 5 most frequently used words in the docstrings of the current namespace
(->> (ns-publics *ns*)
(map (comp :doc meta val))
(remove nil?)
(mapcat (fn [s] (re-seq #"w+" s)))
(frequencies)
(sort-by val)
(reverse)
(take 5)
(map first))
99. Atoms
;; Create atom with initial value
(def a (atom 0))
;; Atomically transition from old to new value
(swap! a (fn [old-value] (+ 3 old-value)))
;; Set to a new value, regardless of old value
(reset! a 22)
100. Refs and Agents
● Refs allow you do many “swap!”s
transactionally
○ aka Software Transactional Memory
● Agents allow you do do “swap!”s
asynchronously on a thread pool
○ a dual of actors: send functions to the value, rather
than values (messages) to the function (actor)
101. core.async
● Go-style communicating sequential
processes
● “select” operator
● Scalable user-space scheduling
● Works in ClojureScript
● See the talk from Clojure Conj here
103. Two kinds of polymorphism
Protocols
Multimethods
Dispatch
The first argument’s type
Arbitrary function of all arguments
Performance
Fast; uses native virtual dispatch
Slow; requires a hash table lookup
Popularity
Extremely popular, good reputation
Used only when arbitrary dispatch is
necessary
104. Protocols
● Solves the expression problem
○ “How can we extend existing functions to new
datatypes and new functions to existing datatypes
without recompiling all code?”
● Uses perfect hashing and Java interfaces for
dispatching
105. Protocols - Example
(defprotocol ITaskRunner
(run [this task] "run the task, which is a fn"))
(defrecord ThreadRunner [name]
ITaskRunner
(run [this task] (future (task)))
(defrecord ImmediateRunner [nickname]
ITaskRunner
(run [this task] (task)))
(run (->ThreadRunner "Bob") (fn [] (println "hello world from thread")))
(run (->ImmediateRunner "Lily") (fn [] (println "hello world from stack")))
106. Protocols - Example
(defprotocol INamed
(named [this] "Return the name of this"))
(extend-protocol INamed
TaskRunner
(named [this] (:name this))
ImmediateRunner
(named [this] (:nickname this)))
(named (->ThreadRunner "Bob"))
;;=> "Bob"
(named (->ImmediateRunner "Lily"))
;;=> "Lily"
107. Multimethods - Example
;; We define a multimethod with its dispatch function
(defmulti battle
"Engage 2 spacecraft in epic battle"
(fn [x y] [(:type x) (:type y)]))
;; We can even create hierarchies of keywords.
;; Java types are permissible as leaves
(derive :x-wing :ship)
108. Multimethods - Example
;; We can define arbitrary numbers of implementations
(defmethod battle [:death-star :planet]
[death-star planet]
(str planet " has been obliterated by " death-star))
(defmethod battle [:ship :star-destroyer]
[ship destroyer]
(str ship " has been eliminated by " destroyer "defenses"))
(defmethod battle [:x-wing :death-star]
[x-wing death-star]
(str x-wing " perfectly shot its proton torpedoes into " death-star))
111. Making your own Exceptions
(try
(throw (ex-info "A data-carrying exception"
{:x 22 :y 42}))
(catch clojure.lang.ExceptionInfo e
(println ":x is" (:x (ex-data e)))))
113. Java Methods vs. Clojure Functions
;; Works
(map str (range 10))
;; Doesn’t work
(map .toString (range 10))
;;Works
(map (fn [x] (.toString x)) (range 10))
114. Clojure Types are Java Types
Clojure Type
Java Type
Long
java.lang.Long
Double
java.lang.Double
Boolean
java.lang.Boolean
String
java.lang.String
Regex
java.util.regex.Pattern
BigDecimal
java.lang.BigDecimal
BigInt
clojure.lang.BigInt (wraps java.lang.BigInteger or long)
115. Clojure Types are Java Types
Clojure Type
Java Type
Function
java.lang.Runnable, java.util.concurrent.Callable
List
java.util.List *
Vector
java.util.List *
Map
java.util.Map *
Set
java.util.Set *
* Does not include mutation operators, like add() or put()
117. How long did it take?
;;Built-in (simple)
(time (dotimes [i 1000] (+ 1 1)))
;;Criterium (statistically robust)
(criterium.core/bench (+ 1 1))
118. Clojurians care about Speed
●
●
●
●
●
Transient collections
Protocols
Unboxed numeric support in the compiler
no.dissassemble (inspect bytecode of fn)
Performance-oriented libraries
○ core.async - user space threading
○ core.matrix - matrix math
○ narrator - time series analysis
119. What’s in your toolkit?
Complex
Simple
State, Objects, Methods
Values, Functions/Namespaces
Variables
Managed references and concurrency
Inheritance, switch, matching
Polymorphism
Syntax
Data
Imperative loops, folds
Sequence Functions
Conditionals
Rules
Inconsistency
Consistency and Design
“Paradigms”
Syntactic Abstraction
126. Paredit + Rainbow Parens
● It’s really hard to keep parens, braces, and
brackets matching
● It’s really hard to see which ones are pairs
● Let your editor handle it!