0
Better Living Through
Clojure
MIT IAP
January 14-15, 2014
We are ….

Bhaskar (Buro) Mookerji
(‘09 VIII , ‘11 VI/MEng)

Aysylu Greenberg
(‘12 VI-2)

David Greenberg
(‘11 XVIII-C)
Today’s agenda includes...
●
●
●
●
●
●

Clojure Overview
Syntax: Everything is Data
Functions
Flow Control
Collections
Seq...
... and tomorrow:
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems S...
Clojure Overview
Rationale and Philosophy
● First released by Rich Hickey in 2007
○ Expressive functional programming with Lisp
○ Designed ...
The familiar solutions are complex
● Complacency breeds incidental complexity
○ Large programs are difficult to understand...
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 ...
Clojure is a Lisp
● LISP: code=data, few primitives, abstraction
○ Local maximum in the hierarchy of expression

● Dynamic...
Clojure is Functional and Dynamic
● Functions are first-class
● All data structures are immutable, persistent,
recursive, ...
Clojure Runs on the JVM (and Javascript!)
● OS independent
● JVM: Well-supported, existing platform, lots
of libraries/pla...
Syntax:
Everything is Data
Atomic Literals
22

;; Long

“derp”

;; String

12345678901

;; BigInt

d e r p

;; Character

1.34

;; Double

#”[0-9]+”
...
Atomic Literals
22

;; Long

“derp”

;; String

12345678901

;; BigInt

d e r p

;; Character

1.34

;; Double

#”[0-9]+”
...
Atomic Literals
22

;; Long

“derp”

;; String

12345678901

;; BigInt

d e r p

;; Character

1.34

;; Double

#”[0-9]+”
...
Atomic Literals
22

;; Long

“derp”

;; String

12345678901

;; BigInt

d e r p

;; Character

1.34

;; Double

#”[0-9]+”
...
Atomic Literals
22

;; Long

“derp”

;; String

12345678901

;; BigInt

d e r p

;; Character

1.34

;; Double

#”[0-9]+”
...
def binds names
user=> pi
;; NOOOOO!! ⇒ Undefined.
CompilerException java.lang.RuntimeException: ...
user=> (def pi 3.1415...
Data Structures
● Lists - singly-linked, front-append
○ (1 2 3 4)

● Vectors - indexed, back-append
○ [:a 2 3 “4”]

● Maps...
Expressions are Data

From: http://alandipert.github.io/oscon2012-clojure/
Expressions are Data

vs…
From: http://alandipert.github.io/oscon2012-clojure/
Expressions are Data
(op ...)
● op can be a ….
○
○
○
○
○

Function: +, mod, println
Macro: when, cond, and
Special Operato...
Function calls use parens...
user=> (defn hello [] "Hi!!!") ;; define hello function
user=> hello
;; return it
#<user$hell...
Quote makes “variables” symbolic
user=> (def x 3)
#'user/x
user=> (+ x 2)
5
user=> '(+ x 2)
(+ x 2)

;; quoted list
;; ret...
Introspect your Environments
user=> (use 'clojure.repl) ;; Quoted symbol
user=> (doc if)
;; Print docstring
--------------...
Introspect your Environments
user=> (source when)
(defmacro when
"Evaluates test. If logical true, evaluates body in an
im...
Namespaces are all around you
● Namespaces disambiguate names
○

vars -> symbols, functions, macros, Java class etc.
are a...
Functions
Functional Abstractions are Useful
● Clojure is functional
● Functions and higher-order functions are
generic in a obvious...
defn binds functions
(defn messenger
;;
([]
;;
(messenger "Hi!"))
;;
([msg]
;;
(println msg))
;;
([msg & args]
;;
(println...
fn creates anonymous functions
● fn creates lambdas
(fn
( (fn
Hi!
nil

[message]

(println message) )

[message]

(println...
apply applies functions
● Invokes argument on arguments (last is a
sequence).
;; & puts rest of args into sequence
;; appl...
let binds symbols to values
● Values are either literal or expressions
● Bound symbols have “lexical scope”
(defn messenge...
Closures
● Allows bindings to persist beyond the lexical
scope
(defn messenger-builder [greeting]
(fn [who] (println greet...
Flow Control
Expressions in Clojure
● Java, etc. : Expressions
return values, but
statements do not.

● Clojure: Everything is an
expre...
Flow Control Operators
● if, when, if-not, when-not, do, cond,
case, etc. are all flow control operators.
● composable and...
“Truthiness”
(if
(if
(if
(if

true :truthy :falsey)
(Object.) :truthy :falsey)
[] :truthy :falsey)
0 :truthy :falsey)

;;=...
if, do, and when
user => (if (even? 5)
;; if is multibranch
(do (println "Even!") ;; do evaluates block and
true)
;; retur...
cond and case
(let [x 22]
;; Compares predicates
(cond
(<= x 22) "Dismissed as coincidence."
(> x 222) "x is greater than ...
Iterations (and side effects)
(dotimes [i 5]
(println i))

;; Evals and returns nil.

(doseq [letter [:a :b :c]
;; Imperat...
Threading Macros Remove Nesting
;; Deeply-nested parens ...
(first (.split (.replace (.toUpperCase "a b c d") "A" "X")
" "...
Recursion (with loop/recur)
● loop binds, recur re-loops
● Strong prefer iteration and higher-order
functions over recursi...
Today ….
●
●
●
●
●
●

Intro to Clojure
Clojure Overview & REPL
Functions
Flow Control
Collections
Sequences
Collections
● Extensive facilities for representing and
manipulating data
● Small number of data structures
● Seq abstract...
Collections: Immutability
● Simple (numbers, strings) and compound
values are immutable
● Key to Clojure's concurrency mod...
Collections: Persistent Data
Structures
● New values = old values + modifications
● New values are not full copies
● New v...
Collections: Persistent Data
Structures

http://eclipsesource.com/blogs/2009/12/13/persistent-trees-in-git-clojure-and-cou...
Collections: Data Structures
● Sequential: list
Collections: Data Structures
● Sequential: list
○
○
○
○

Singly-linked lists
Prepend: O(1)
Lookup: O(1) at head, O(n) anyw...
Collections: Data Structures
● Sequential: list
()

;=> the empty list

(:a :b :c)

; error because :a not function

'(:a ...
Collections: Data Structures
● Sequential: list, vector
Collections: Data Structures
● Sequential: list, vector
○
○
○
○

Indexed, random-access, array-like
Append: O(1) *
Lookup:...
Collections: Data Structures
● Sequential: list, vector
[]
;=> the empty vector
[:a :b :c]
;=> [:a :b :c]
(vector :a :b :c...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
Collections: Data Structures
● Sequential: list, vector
● Associative: map
○ Key → value, hash table, dictionary
○ Insert ...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
{}
{:a "a" :b "b"}
(get {:a "a"} :a)
(get {:a "...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
○ Nested access: get-in, assoc-in, update-in
(d...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
○ Nested access: get-in, assoc-in, update-in
(d...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
○ Nested access: get-in, assoc-in, update-in
(d...
Collections: Data Structures
● Sequential: list, vector
● Associative: map
○ Nested access: get-in, assoc-in, update-in
(d...
Collections: Data Structures
● Sequential: list, vector
● Associative: map, set
Collections: Data Structures
● Sequential: list, vector
● Associative: map, set
○
○
○
○

Set of distinct values
Insert: O(...
Collections: Data Structures
● Sequential: list, vector
● Associative: map, set
#{}
#{"a" "b"}

;;=> the empty set
;;=> #{...
Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b...
Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b...
Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b)
;;=> "b...
Collections: Data Structures are
Functions
● Maps are functions of their keys
(def dict {:a "a" :b "b"})
(dict :b) ;;=> "b...
Collections: Destructuring
● Declarative way to pull apart compound data
○ vs. explicit, verbose access

● Sequential & as...
Collections: Destructuring
;; Without destructuring:
(defn next-fib-pair [pair]
[(second pair) (+ (first pair) (second pai...
Collections: Destructuring
;; Without destructuring:
(defn next-fib-pair [pair]
[(second pair) (+ (first pair) (second pai...
Today ….
●
●
●
●
●
●
●

Intro to Clojure
Clojure Overview & REPL
Functions
Flow Control
Names & Namespaces
Collections
Seq...
Sequences
● Abstraction for representing iteration
● Backed by a data structure or a function
○ Can be lazy and/or "infini...
Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil
Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil

● ...
Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil

● ...
Sequences: API
● (seq coll)
○ If collection is not empty, return seq object on it
○ If collection is empty, return nil

● ...
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})

;=> (...
Sequences: Over Structures
● We can treat any data structure as a seq
(def s '(1 2 3))

; s is a list

s

1

2

3
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
; ...
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 ...
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...
Sequences: Over Structures
● We can treat any data structure as a seq
○ Lists are seqs
○ Others are wrapped
○ Associative ...
Sequences: Over Functions
● Can map a generator function to a seq
● Seq is lazy, can be infinite
● Can process more than f...
Sequences: Generation
(range)

;=> (0 1 2 ... infinite

(range 5)

;=> (0 1 2 3 4)

(repeat :b)

;=> (:b :b :b ... infinit...
Sequences: Into Collections
(into #{} "hello")

;=> #{e h l o}

(into {} [[:x 1] [:y 2]]) ;=> {:x 1, :y 2}
(into () [:a :b...
Sequences: Shorten
(take 3 (range)) ;=> (0 1 2)
(drop 3 (range)) ;=> (3 4 5 ... infinite
(filter even? (range)) ;=> (0 2 4...
Sequences: Lengthen
(concat [:a :b] (range 2 5))
(cycle [:a :b :c])
(interpose , (range 3))

;=> (:a :b 2 3 4)

;=> (:a :b...
Sequences: map
(map even? (range 1 5))

;=> (false true false true)

(map + [1 2 3] [4 5 6]) ;=> (5 7 9)
(map * [1 2 3] (r...
Sequences: reduce
(reduce function init seq)
●
●
●
●

function takes 2 arguments: accumulator and the current argument
red...
Sequences: some
(some even? [1 2 3 4]) ;=> true
(some #{:foo} [:baz :bar :foo]) ;=> :foo
Combine sequence functions: Power
;; Sum of the first 50 odd integers
(reduce + (take 50 (filter odd? (range)))) ;=> 2500
...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
clojure.test
(deftest math-basics
(is (= 3 (+ 1 2)))
(is (= 10 (* 2 5)))
(is (thrown? java.lang.ArithmeticException (/ 1 0...
midje
(fact
(+ 1 2) => 3
(* 2 5) => 10
(/ 1 0) => (throws java.lang.ArithmeticException))
expectations
(expect 3 (+ 1 2))
(expect 10 (* 2 5))
(expect java.lang.ArithmeticException (/ 1 0))
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Benefits of Immutability
● What is a race
condition?
● How does
immutability
help?
Atoms
;; Create atom with initial value
(def a (atom 0))
;; Atomically transition from old to new value
(swap! a (fn [old-...
Refs and Agents
● Refs allow you do many “swap!”s
transactionally
○ aka Software Transactional Memory

● Agents allow you ...
core.async
● Go-style communicating sequential
processes
● “select” operator
● Scalable user-space scheduling
● Works in C...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Two kinds of polymorphism
Protocols

Multimethods

Dispatch

The first argument’s type

Arbitrary function of all argument...
Protocols
● Solves the expression problem
○ “How can we extend existing functions to new
datatypes and new functions to ex...
Protocols - Example
(defprotocol ITaskRunner
(run [this task] "run the task, which is a fn"))
(defrecord ThreadRunner [nam...
Protocols - Example
(defprotocol INamed
(named [this] "Return the name of this"))
(extend-protocol INamed
TaskRunner
(name...
Multimethods - Example
;; We define a multimethod with its dispatch function
(defmulti battle
"Engage 2 spacecraft in epic...
Multimethods - Example
;; We can define arbitrary numbers of implementations
(defmethod battle [:death-star :planet]
[deat...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Exceptions
(try
(do-something-that-could-fail)
(catch RuntimeException e
(print-stack-trace e))
(finally
(dispose-of-resou...
Making your own Exceptions
(try
(throw (ex-info "A data-carrying exception"
{:x 22 :y 42}))
(catch clojure.lang.ExceptionI...
Java Interop
Task

Java

Clojure

Instantiation

new MyClass(“foo”)

(MyClass. “foo”)

Instance method

dog.bark()

(.bark...
Java Methods vs. Clojure Functions
;; Works
(map str (range 10))
;; Doesn’t work
(map .toString (range 10))
;;Works
(map (...
Clojure Types are Java Types
Clojure Type

Java Type

Long

java.lang.Long

Double

java.lang.Double

Boolean

java.lang.B...
Clojure Types are Java Types
Clojure Type

Java Type

Function

java.lang.Runnable, java.util.concurrent.Callable

List

j...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
How long did it take?
;;Built-in (simple)
(time (dotimes [i 1000] (+ 1 1)))
;;Criterium (statistically robust)
(criterium....
Clojurians care about Speed
●
●
●
●
●

Transient collections
Protocols
Unboxed numeric support in the compiler
no.dissasse...
What’s in your toolkit?
Complex

Simple

State, Objects, Methods

Values, Functions/Namespaces

Variables

Managed referen...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Leiningen
●

“for automating Clojure projects without setting your hair on fire”

●

Functional project management

●

Fet...
Leingen - usage
lein
lein
lein
lein

new my-cool-project
repl
uberjar
deploy clojars

(defproject my-cool-project "0.1.0-S...
Vim
● fireplace
○
○
○
○

Simple evaluation
Prefix intellisense
Documentation lookup
Go to source

● redl
○ Advanced REPL w...
Emacs
● cider
○
○
○
○

Advanced REPL
Documentation lookup
Symbol completion
Source lookup

● ritz
○ Stepping debugger via ...
Light Table
●
●
●
●

Easiest to get started
REPL
Inline documentation
Written in Clojure(Script)!
Paredit + Rainbow Parens
● It’s really hard to keep parens, braces, and
brackets matching
● It’s really hard to see which ...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Clojure Toolbox
● clojure-toolbox.com
● Great starting point for projects!
● Database clients, web frameworks, data
struct...
● Purely functional
database
● Horizontal read
scalability
Storm
● Hadoop for realtime data
● Used by Twitter to
process all tweets in
real-time (and by
many others!)
Riemann
● Event processor and monitoring tool for
distributed systems
● Makes it easy to monitor clusters, calculate
stati...
Instaparse
What if context-free grammars were as easy to
use as regular expressions?
(insta/parser
"S = AB*
AB = A B
A = '...
In this Class
●
●
●
●
●
●
●
●

Testing
Concurrency
Polymorphism
JVM Interop
Performance
Tooling
Interesting Problems Solve...
Sources
● http://clojure.org
● Talks by Rich Hickey: Clojure, Are We There
Yet, and Simple Made Easy
● Beating the Average...
Upcoming SlideShare
Loading in...5
×

Clojure class

1,913

Published on

Published in: Technology
1 Comment
7 Likes
Statistics
Notes
No Downloads
Views
Total Views
1,913
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
40
Comments
1
Likes
7
Embeds 0
No embeds

No notes for slide

Transcript of "Clojure class"

  1. 1. Better Living Through Clojure MIT IAP January 14-15, 2014
  2. 2. We are …. Bhaskar (Buro) Mookerji (‘09 VIII , ‘11 VI/MEng) Aysylu Greenberg (‘12 VI-2) David Greenberg (‘11 XVIII-C)
  3. 3. Today’s agenda includes... ● ● ● ● ● ● Clojure Overview Syntax: Everything is Data Functions Flow Control Collections Sequences
  4. 4. ... and tomorrow: ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  5. 5. Clojure Overview
  6. 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. 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. 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. 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. 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. 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
  12. 12. Syntax: Everything is Data
  13. 13. Atomic Literals 22 ;; Long “derp” ;; String 12345678901 ;; BigInt d e r p ;; Character 1.34 ;; Double #”[0-9]+” ;; Regex 1.34M ;; BigDecimal :derp, ::derp ;; Keyword 22/3 ;; Ratio nil ;; null true ;; boolean
  14. 14. Atomic Literals 22 ;; Long “derp” ;; String 12345678901 ;; BigInt d e r p ;; Character 1.34 ;; Double #”[0-9]+” ;; Regex 1.34M ;; BigDecimal :derp, ::derp ;; Keyword 22/2 ;; Ratio nil ;; null true ;; boolean Evaluating literals in the REPL: user=> 22 22 user=> ;; ;; ;; ;; Read Eval Print Loop
  15. 15. Atomic Literals 22 ;; Long “derp” ;; String 12345678901 ;; BigInt d e r p ;; Character 1.34 ;; Double #”[0-9]+” ;; Regex 1.34M ;; BigDecimal :derp, ::derp ;; Keyword 22/2 ;; Ratio nil ;; null true ;; boolean Evaluating expressions: user=> (+ 2 2) 4 user=> ;; ;; ;; ;; Read Eval Print Loop
  16. 16. Atomic Literals 22 ;; Long “derp” ;; String 12345678901 ;; BigInt d e r p ;; Character 1.34 ;; Double #”[0-9]+” ;; Regex 1.34M ;; BigDecimal :derp, ::derp ;; Keyword 22/2 ;; Ratio nil ;; null true ;; boolean Evaluating expressions: user=> ::derp :user/derp user=> ;; ;; ;; ;; Read Eval Print Loop
  17. 17. Atomic Literals 22 ;; Long “derp” ;; String 12345678901 ;; BigInt d e r p ;; Character 1.34 ;; Double #”[0-9]+” ;; Regex 1.34M ;; BigDecimal :derp, ::derp ;; Keyword 22/2 ;; Ratio nil ;; null true ;; boolean Evaluating expressions: user=> (class ::derp) clojure.lang.Keyword user=>
  18. 18. def binds names user=> pi ;; NOOOOO!! ⇒ Undefined. CompilerException java.lang.RuntimeException: ... user=> (def pi 3.1415926) #'user/pi user=> pi 3.1415926 user=> (println pi) 3.1415926 nil
  19. 19. Data Structures ● Lists - singly-linked, front-append ○ (1 2 3 4) ● Vectors - indexed, back-append ○ [:a 2 3 “4”] ● Maps - key/value store ○ {:a 2 :b 4} ● Sets ○ #{:a :b :c :d}
  20. 20. Expressions are Data From: http://alandipert.github.io/oscon2012-clojure/
  21. 21. Expressions are Data vs… From: http://alandipert.github.io/oscon2012-clojure/
  22. 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. 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. 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. 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. 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. 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)]))
  28. 28. Functions
  29. 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. 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?")
  31. 31. fn creates anonymous functions ● fn creates lambdas (fn ( (fn Hi! nil [message] (println message) ) [message] (println message) ) “Hi!”)
  32. 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. 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. 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!
  35. 35. Flow Control
  36. 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. 37. Flow Control Operators ● if, when, if-not, when-not, do, cond, case, etc. are all flow control operators. ● composable and general
  38. 38. “Truthiness” (if (if (if (if true :truthy :falsey) (Object.) :truthy :falsey) [] :truthy :falsey) 0 :truthy :falsey) ;;=> :truthy, and so are: ;; objects ;; empty collections ;; zero (if false :truthy :falsey) (if nil :truthy :falsey) (if (seq []) :truthy :falsey) ;;=> :falsey ;; nil ;; seq on empty collection (and true 0 22) ;; returns last expression (or true false 22)
  39. 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. 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
  41. 41. Iterations (and side effects) (dotimes [i 5] (println i)) ;; Evals and returns nil. (doseq [letter [:a :b :c] ;; Imperative cartesian product. number (range 5)] (println [letter number])) (for [letter [:a :b :c] number (range 5)] [letter number]) ;; Sequence cartesian product. ;; ([:a 0] [:a 1] [:a 2] [:b 0] ;; [:b 1] [:b 2] …)
  42. 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. 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
  44. 44. Today …. ● ● ● ● ● ● Intro to Clojure Clojure Overview & REPL Functions Flow Control Collections Sequences
  45. 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. 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. 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
  48. 48. Collections: Persistent Data Structures http://eclipsesource.com/blogs/2009/12/13/persistent-trees-in-git-clojure-and-couchdb-data-structureconvergence/
  49. 49. Collections: Data Structures ● Sequential: list
  50. 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. 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)
  52. 52. Collections: Data Structures ● Sequential: list, vector
  53. 53. Collections: Data Structures ● Sequential: list, vector ○ ○ ○ ○ Indexed, random-access, array-like Append: O(1) * Lookup: O(1) * Grow at the tail (end) O(1) * = O(log 32 n), really close to O(1), is O(1) for n < 1 billion
  54. 54. Collections: Data Structures ● Sequential: list, vector [] ;=> the empty vector [:a :b :c] ;=> [:a :b :c] (vector :a :b :c) ;=> [:a :b :c] (vec '(:a :b :c)) ;=> [:a :b :c] (nth [:a :b :c] 0) ;=> :a (conj [:a :b] :c) ;=> [:a :b :c]
  55. 55. Collections: Data Structures ● Sequential: list, vector ● Associative: map
  56. 56. Collections: Data Structures ● Sequential: list, vector ● Associative: map ○ Key → value, hash table, dictionary ○ Insert and lookup: O(1) * ○ Unordered
  57. 57. Collections: Data Structures ● Sequential: list, vector ● Associative: map {} {:a "a" :b "b"} (get {:a "a"} :a) (get {:a "a"} :z) (get {:a "a"} :z 22) ;;=> the empty map ;;=> {:a "a" :b "b"} ;;=> "a" ;;=> nil ; not found ;;=> 22 ; default (assoc {:a "a"} :b "b") ;;=> {:a "a" :b "b"} (dissoc {:a "a"} :a) ;;=> {} (conj {} [:a "a"]) ;;=> {:a "a"}
  58. 58. Collections: Data Structures ● Sequential: list, vector ● Associative: map ○ Nested access: get-in, assoc-in, update-in (def our-class {:class "Better Living Through Clojure" :location {:room "4-231"})
  59. 59. Collections: Data Structures ● Sequential: list, vector ● Associative: map ○ Nested access: get-in, assoc-in, update-in (def our-class {:class "Better Living Through Clojure" :location {:room "4-231"}) (get (get our-class :location) :room) ;;=> "4-231"
  60. 60. Collections: Data Structures ● Sequential: list, vector ● Associative: map ○ Nested access: get-in, assoc-in, update-in (def our-class {:class "Better Living Through Clojure" :location {:room "4-231"}) (get (get our-class :location) :room) ;;=> "4-231" (-> our-class (get :location) (get :room)) ;;=> "4-231"
  61. 61. Collections: Data Structures ● Sequential: list, vector ● Associative: map ○ Nested access: get-in, assoc-in, update-in (def our-class {:class "Better Living Through Clojure" :location {:room "4-231"}) (get (get our-class :location) :room) ;;=> "4-231" (-> our-class (get :location) (get :room)) ;;=> "4-231" (get-in our-class [:location :room]) ;;=> "4-231"
  62. 62. Collections: Data Structures ● Sequential: list, vector ● Associative: map, set
  63. 63. Collections: Data Structures ● Sequential: list, vector ● Associative: map, set ○ ○ ○ ○ Set of distinct values Insert: O(1) * Member?: O(1) * Unordered
  64. 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. 65. Collections: Data Structures are Functions ● Maps are functions of their keys (def dict {:a "a" :b "b"}) (dict :b) ;;=> "b"
  66. 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. 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. 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. 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
  70. 70. Collections: Destructuring ;; Without destructuring: (defn next-fib-pair [pair] [(second pair) (+ (first pair) (second pair))])
  71. 71. Collections: Destructuring ;; Without destructuring: (defn next-fib-pair [pair] [(second pair) (+ (first pair) (second pair))]) ;; With destructuring: (defn next-fib-pair [[x y]] [y (+ x y)])
  72. 72. Today …. ● ● ● ● ● ● ● Intro to Clojure Clojure Overview & REPL Functions Flow Control Names & Namespaces Collections Sequences
  73. 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. 74. Sequences: API ● (seq coll) ○ If collection is not empty, return seq object on it ○ If collection is empty, return nil
  75. 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. 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. 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. 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
  79. 79. Sequences: Over Structures ● We can treat any data structure as a seq (def s '(1 2 3)) ; s is a list s 1 2 3
  80. 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. 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. 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. 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. 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
  85. 85. Sequences: Generation (range) ;=> (0 1 2 ... infinite (range 5) ;=> (0 1 2 3 4) (repeat :b) ;=> (:b :b :b ... infinite (repeatedly #(rand-int 100)) ;=> (89 58 73 ... infinite
  86. 86. Sequences: Into Collections (into #{} "hello") ;=> #{e h l o} (into {} [[:x 1] [:y 2]]) ;=> {:x 1, :y 2} (into () [:a :b :c]) ;=> (:c :b :a)
  87. 87. Sequences: Shorten (take 3 (range)) ;=> (0 1 2) (drop 3 (range)) ;=> (3 4 5 ... infinite (filter even? (range)) ;=> (0 2 4 6 ... infinite (remove even? (range)) ;=> (1 3 5 7 ... infinite
  88. 88. Sequences: Lengthen (concat [:a :b] (range 2 5)) (cycle [:a :b :c]) (interpose , (range 3)) ;=> (:a :b 2 3 4) ;=> (:a :b :c :a :b ... infinite ;=> (0 , 1 , 2)
  89. 89. Sequences: map (map even? (range 1 5)) ;=> (false true false true) (map + [1 2 3] [4 5 6]) ;=> (5 7 9) (map * [1 2 3] (range 1000)) ;=> (0 2 6)
  90. 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
  91. 91. Sequences: some (some even? [1 2 3 4]) ;=> true (some #{:foo} [:baz :bar :foo]) ;=> :foo
  92. 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))
  93. 93. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  94. 94. clojure.test (deftest math-basics (is (= 3 (+ 1 2))) (is (= 10 (* 2 5))) (is (thrown? java.lang.ArithmeticException (/ 1 0))))
  95. 95. midje (fact (+ 1 2) => 3 (* 2 5) => 10 (/ 1 0) => (throws java.lang.ArithmeticException))
  96. 96. expectations (expect 3 (+ 1 2)) (expect 10 (* 2 5)) (expect java.lang.ArithmeticException (/ 1 0))
  97. 97. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  98. 98. Benefits of Immutability ● What is a race condition? ● How does immutability help?
  99. 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. 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. 101. core.async ● Go-style communicating sequential processes ● “select” operator ● Scalable user-space scheduling ● Works in ClojureScript ● See the talk from Clojure Conj here
  102. 102. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  103. 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. 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. 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. 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. 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. 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))
  109. 109. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  110. 110. Exceptions (try (do-something-that-could-fail) (catch RuntimeException e (print-stack-trace e)) (finally (dispose-of-resources)))
  111. 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)))))
  112. 112. Java Interop Task Java Clojure Instantiation new MyClass(“foo”) (MyClass. “foo”) Instance method dog.bark() (.bark dog) Instance field object.field (.-field object) Static method Math.sin(22) (Math/sin 22) Static field Math.PI Math/PI
  113. 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. 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. 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()
  116. 116. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  117. 117. How long did it take? ;;Built-in (simple) (time (dotimes [i 1000] (+ 1 1))) ;;Criterium (statistically robust) (criterium.core/bench (+ 1 1))
  118. 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. 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
  120. 120. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  121. 121. Leiningen ● “for automating Clojure projects without setting your hair on fire” ● Functional project management ● Fetches dependencies and constructs classpath ● Packages and deploys project ● Easily extensible with plugins
  122. 122. Leingen - usage lein lein lein lein new my-cool-project repl uberjar deploy clojars (defproject my-cool-project "0.1.0-SNAPSHOT" ... :dependencies [[org.clojure/clojure "1.4.0"] [ring "1.2.1"]])
  123. 123. Vim ● fireplace ○ ○ ○ ○ Simple evaluation Prefix intellisense Documentation lookup Go to source ● redl ○ Advanced REPL with simple debugger ○ Fuzzy intellisense
  124. 124. Emacs ● cider ○ ○ ○ ○ Advanced REPL Documentation lookup Symbol completion Source lookup ● ritz ○ Stepping debugger via JVM’s debugging API ○ All features of cider
  125. 125. Light Table ● ● ● ● Easiest to get started REPL Inline documentation Written in Clojure(Script)!
  126. 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!
  127. 127. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  128. 128. Clojure Toolbox ● clojure-toolbox.com ● Great starting point for projects! ● Database clients, web frameworks, data structures, parsers, etc.
  129. 129. ● Purely functional database ● Horizontal read scalability
  130. 130. Storm ● Hadoop for realtime data ● Used by Twitter to process all tweets in real-time (and by many others!)
  131. 131. Riemann ● Event processor and monitoring tool for distributed systems ● Makes it easy to monitor clusters, calculate statistics, and send alerts
  132. 132. Instaparse What if context-free grammars were as easy to use as regular expressions? (insta/parser "S = AB* AB = A B A = 'a'+ B = 'b'+")
  133. 133. In this Class ● ● ● ● ● ● ● ● Testing Concurrency Polymorphism JVM Interop Performance Tooling Interesting Problems Solved by Clojure Our Projects
  134. 134. Sources ● http://clojure.org ● Talks by Rich Hickey: Clojure, Are We There Yet, and Simple Made Easy ● Beating the Averages, Paul Graham
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×