Cracking ClojureAlex MillerRevelytix
Clojure• A Lisp on the JVM (also ClojureScript on JavaScript)
• Dynamic (types, code, etc)• Functional language• Compiled (there is no interpreter)• Immutability and state management• Code is data • REPL - Read / Eval / Print / Loop• Interactive development
2
It looks like this...
3
(defn neighbors [[x y]] (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])] [(+ dx x) (+ dy y)]))
(defn live [n alive?] (or (= n 3) (and (= n 2) alive?)))
(defn step [world] (set (for [[cell n] (frequencies (mapcat neighbors world)) :when (live n (world cell))] cell)))
(defn life [initial-world] (iterate step initial-world))
Primitives
4
Collections
5
Sequences
6
Sequences
6
Functions
7
Functions
7
Functions
7
Compiler
8
Casting spells
9
Creating functions
10
Creating functions
10
Creating functions
10
Creating functions
10
Creating functions
10
An example...
11
map
12
Sequence of lines
13
Sequence of files
14
Sequence of files
14
Sequence functions
15
You
16
Lazy sequences
17
18
18
Power
19
Objects
20
Maps as cheap objects
21
Records
22
Java
23
package domain;
public class Beer { private String beer; private String brewery; private float alcohol; private int ibu; public Beer(String beer, String brewery, float alcohol, int ibu) { super(); this.beer = beer; this.brewery = brewery; this.alcohol = alcohol; this.ibu = ibu; }
public String getBeer() { return beer; } public String getBrewery() { return brewery; } public float getAlcohol() { return alcohol; } public int getIbu() { return ibu; } public void setBeer(String beer) { this.beer = beer; } public void setBrewery(String brewery) { this.brewery = brewery; } public void setAlcohol(float alcohol) { this.alcohol = alcohol; } public void setIbu(int ibu) { this.ibu = ibu; }
@Override public int hashCode() { final int prime = 31;
int result = 1; result = prime * result + Float.floatToIntBits(alcohol); result = prime * result + ((beer == null) ? 0 : beer.hashCode()); result = prime * result + ((brewery == null) ? 0 : brewery.hashCode()); result = prime * result + ibu; return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Beer other = (Beer) obj; if (Float.floatToIntBits(alcohol) != Float .floatToIntBits(other.alcohol)) return false; if (beer == null) { if (other.beer != null) return false; } else if (!beer.equals(other.beer)) return false; if (brewery == null) { if (other.brewery != null) return false; } else if (!brewery.equals(other.brewery)) return false; if (ibu != other.ibu) return false; return true; }
@Override public String toString() { return "Beer [beer=" + beer + ", brewery=" + brewery + ", alcohol=" + alcohol + ", ibu=" + ibu + "]"; }}
Java
23
package domain;
public class Beer { private String beer; private String brewery; private float alcohol; private int ibu; public Beer(String beer, String brewery, float alcohol, int ibu) { super(); this.beer = beer; this.brewery = brewery; this.alcohol = alcohol; this.ibu = ibu; }
public String getBeer() { return beer; } public String getBrewery() { return brewery; } public float getAlcohol() { return alcohol; } public int getIbu() { return ibu; } public void setBeer(String beer) { this.beer = beer; } public void setBrewery(String brewery) { this.brewery = brewery; } public void setAlcohol(float alcohol) { this.alcohol = alcohol; } public void setIbu(int ibu) { this.ibu = ibu; }
@Override public int hashCode() { final int prime = 31;
int result = 1; result = prime * result + Float.floatToIntBits(alcohol); result = prime * result + ((beer == null) ? 0 : beer.hashCode()); result = prime * result + ((brewery == null) ? 0 : brewery.hashCode()); result = prime * result + ibu; return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Beer other = (Beer) obj; if (Float.floatToIntBits(alcohol) != Float .floatToIntBits(other.alcohol)) return false; if (beer == null) { if (other.beer != null) return false; } else if (!beer.equals(other.beer)) return false; if (brewery == null) { if (other.brewery != null) return false; } else if (!brewery.equals(other.brewery)) return false; if (ibu != other.ibu) return false; return true; }
@Override public String toString() { return "Beer [beer=" + beer + ", brewery=" + brewery + ", alcohol=" + alcohol + ", ibu=" + ibu + "]"; }}
Fields and types
Construction
Getters
Setters
Hashing
Equality
Printing
Data interfaces
24
Data interfaces
24
Data interfaces
25
Data - Clojure vs Java
26
Data - Clojure vs Java
26
Polymorphism
27
Generic access FTW
28
Multimethods
29
Multimethod dispatch
30
Protocols
31
State
32
Atoms
33
Refs
34
Agents
35
Destructuring
36
for comprehensions
37
for comprehensions
37
Macros
38
Macros
39
Review
40
DATA CODE
HOSTCONCURRENCY
Review
40
DATA CODE
HOSTCONCURRENCY
primitives
Review
40
DATA CODE
HOSTCONCURRENCY
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
sequences
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
sequences
laziness
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
sequences
laziness
FP
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
sequences
lazinesssequence library
FP
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
recordstypes
sequences
lazinesssequence library
FP
primitives
collections
Review
40
DATA CODE
HOSTCONCURRENCY
recordstypes
sequences
lazinesssequence library
FP
primitives
collections
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
primitives
collections
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
primitives
collections
destructuring
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
macros
primitives
collections
destructuring
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
metadata
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
macros
primitives
collections
transientsdestructuring
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
metadata
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
macros
primitives
collections
transientsdestructuring
namespaces
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
metadata
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
macros
primitives
collections
transientsdestructuring
namespaces
recursion
multimethodsprotocols
Review
40
DATA CODE
HOSTCONCURRENCY
metadata
recordstypes
atoms
state
refs agents
sequences
lazinesssequence library
FP
macros
primitives
collections
transientsdestructuring
namespaces
recursion
multimethodsprotocols
Java interop
Java libs
Review
40
DATA CODE
HOSTCONCURRENCY
metadata
recordstypes
atoms
state
refs agents
sequences
laziness
futures promises
pmap
sequence library
FP
macros
primitives
collections
transientsdestructuring
namespaces
recursion
multimethodsprotocols
Java interop
Java libs
Conway's Life
41
Implementation courtesy of Christophe Grandhttp://clj-me.cgrand.net/2011/08/19/conways-game-of-life/
"Blinker" configuration
Life's rules: If alive and 2 or 3 neighbors Then stay alive Else die If dead and 3 neighbors Then come to life
Thanks!
• Twitter: @puredanger• Blog: http://tech.puredanger.com• Work: http://revelytix.com• My conferences
– Strange Loop - http://thestrangeloop.com– Clojure/West - http://clojurewest.com
If you want to pair on Clojure during Devoxx, ping me on Twitter!
43