More Related Content Similar to Clojure: Towards The Essence of Programming (20) More from Howard Lewis Ship (9) Clojure: Towards The Essence of Programming4. essence
noun
the intrinsic nature or indispensable quality of
something, esp. something abstract, that
determines its character : conflict is the essence of
drama.
4 © 2010 Howard Lewis Ship
5. Mainstream Programming
Applications
Frameworks
Libraries
Language
Operating System
5 © 2010 Howard Lewis Ship
6. Ceremony
vs.
Essence
6 © 2010 Howard Lewis Ship
8. … holding
you back?
8 © 2010 Howard Lewis Ship
9. Java: Data Encapsulated in Objects
Stock Stock Stock
ticker: AAPL ticker: MSFT ticker: ORCL
lastTrade: 203.25 lastTrade: 29.12 lastTrade: 21.90
open: 204.50 open: 29.08 open: 21.83
shares: 100 shares: 50 shares: 200
public static void sortByLastTrade(List<Stock> portfolio)
{
Comparator<Stock> c = new Comparator<Stock>()
{
public int compare(Stock o1, Stock o2)
{
public static void sortByOpen(List<Stock> portfolio)
return o1.getLastTrade() - o2.getLastTrade();
{
}
Comparator<Stock> c = new Comparator<Stock>()
};
{
public int compare(Stock o1, Stock o2)
Collections.sort(portfolio, c);
{
}
return o1.getOpen() - o2.getOpen();
}
};
Collections.sort(portfolio, c);
}
9 © 2010 Howard Lewis Ship
10. Clojure: Data in Maps and Lists
:ticker AAPL :ticker MSFT :ticker ORCL
:last-trade 203.25 :last-trade 29.12 :last-trade 21.90
{ :open 204.50 } { :open 29.08 }{ :open 21.83 }
:shares 100 :shares 50 :shares 200
user=> portfolio
[{:ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200}]
user=> (sort-by :last-trade portfolio)
({:ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200}
{:ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100})
user=> (sort-by :shares portfolio)
({:ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200})
user=>
10 © 2010 Howard Lewis Ship
11. Functional JavaScript
var portfolio = [ { ticker: "AAPL", lastTrade: 203.25, open: 204.50},
{ ticker: "MSFT", lastTrade: 29.12, open: 29.08 },
{ ticker: "ORCL", lastTrade: 21.90, open: 21.83 } ]
portfolio.sortBy(function (stock) { return stock.lastTrade }).toJSON()
[{"ticker": "ORCL", "lastTrade": 21.9, "open": 21.83},
{"ticker": "MSFT", "lastTrade": 29.12, "open": 29.08},
{"ticker": "AAPL", "lastTrade": 203.25, "open": 204.5}]
11 © 2010 Howard Lewis Ship
13. Reading Lisp
(defn render-json
"Renders JSON content (typically, a map or a seq) as the
response. The response content type is set to
"application/json". Returns true."
[env json-value]
(let [response (-> env :servlet-api :response)]
(.setContentType response "application/json")
(with-open [writer (.getWriter Aargh!
response)]
(binding [*out* writer]
(print-json json-value))))
true)
13 © 2010 Howard Lewis Ship
14. Structural View
defn render-json env json-value
let
response -> env :servlet-api :response
.setContentType response "application/json"
with-open
writer .getWriter response
binding
*out* writer
print-json json-value
14 © 2010 Howard Lewis Ship
15. Java: Complex Structure
int f = 9 * c / 5 + 32;
Higher precendence, then left to right: ((9 * c) / 5) + 32
+
(+
/ 32 (/
(* 9 c)
* 5 5)
32)
9 c
15 © 2010 Howard Lewis Ship
17. Code is Data
Quoted list of
'(1 2 3) numbers
(biggest 5 42) Function call
Function definition
(defn biggest
"Find the maximum of two numbers"
[x y]
(if (> x y) x y))
17 © 2010 Howard Lewis Ship
18. Read Eval Print Loop
user=> (defn biggest
"Find the maximum of two numbers"
[x y]
(if (> x y) x y))
#=(var user/biggest)
user=> (biggest 5 42)
42
user=> (doc biggest)
-------------------------
user/biggest
([x y])
Find the maximum of two numbers
nil
user=> '(1 2 3)
(1 2 3)
user=> '(biggest 5 42)
(biggest 5 42)
user=> (first '(biggest 5 42))
biggest
user=> (eval '(biggest 5 42))
42
18 © 2010 Howard Lewis Ship
19. REPL and Compilation
Source Code
Repl Input Clojure
User Classes Java
Evaluator
Compiler
Clojure
Source Files Java Libraries
JVM
Operating System
19 © 2010 Howard Lewis Ship
20. Clojure Literals
user=> "A Clojure String"
"A Clojure String"
user=> space
space
user=> A
A
user=> nil Java null
nil
user=> :balance
:balance
user=> true
true
user=> false
false
20 © 2010 Howard Lewis Ship
21. Numeric Literals
user=> 5
5
user=> 5.001
5.001
Ratio user=> 22/7
22/7
user=> (* 2 22/7)
44/7
user=> (* 100000 100000 100000) BigInteger
1000000000000000
user=> (+ 5. 0.000000000000000001)
5.0
user=> (+ 5.0M 0.000000000000000001M)
5.000000000000000001M
BigDecimal
21 © 2010 Howard Lewis Ship
22. Java Interop: Function Calls
(.method-name receiver arguments…)
factory.setNamespaceAware(true)
factory.newSaxParser().parse(src, handler)
( .. factory newSaxParser (
(.. (parse src handler))
))
22 © 2010 Howard Lewis Ship
23. Clojure Collections: Lists
4
lst
user=> (def lst '(1 2 3))
#=(var user/lst)
user=> lst
(1 2 3)
user=> (first lst)
1 1
user=> (rest lst)
(2 3)
user=> (conj lst 4) 2
(4 1 2 3)
user=> (cons 4 lst)
(4 1 2 3) 3
23 © 2010 Howard Lewis Ship
24. Clojure Collections: Vectors
user=> (def v [:moe :larry :curly])
#=(var user/v)
user=> v
[:moe :larry :curly]
user=> (first v)
:moe
user=> (rest v)
(:larry :curly)
user=> (conj v :shemp)
[:moe :larry :curly :shemp]
user=> (cons :shemp v)
(:shemp :moe :larry :curly)
user=> v
[:moe :larry :curly]
24 © 2010 Howard Lewis Ship
25. Clojure Collections: Maps
user=> (def m {:first-name "Howard" :last-name "Lewis Ship"})
#=(var user/m)
user=> m
{:last-name "Lewis Ship", :first-name "Howard"}
user=> (get m :last-name)
"Lewis Ship"
user=> (assoc m :company "TWD")
{:company "TWD", :last-name "Lewis Ship", :first-name "Howard"}
user=> m
{:last-name "Lewis Ship", :first-name "Howard"}
user=> (get m:ssn)
nil
25 © 2010 Howard Lewis Ship
26. Clojure Collections: Sets
user=> (def s #{"Howard" "Suzanne" "Molly" "Jim"})
#=(var user/s)
user=> s
#{"Howard" "Jim" "Molly" "Suzanne"}
user=> (contains? s "Howard")
true
user=> (contains? s "howard")
false
user=> (conj s "Howard")
#{"Howard" "Jim" "Molly" "Suzanne"}
user=> (conj s "Scott")
#{"Howard" "Jim" "Molly" "Suzanne" "Scott"}
26 © 2010 Howard Lewis Ship
28. My First Program
No it
10 X = 1 doesn't!
20 PRINT X
30 X = X + 1
40 GOTO 20
28 © 2010 Howard Lewis Ship
33. Functional Java Collections
public interface Predicate<T>
{
boolean accept(T value);
}
public static <T> Collection<T> filter(Predicate<T> pred, Collection<T> coll)
{
Collection<T> out = new ArrayList<T>();
for (T item : coll)
{
if (pred.accept(item))
out.add(item);
}
return out;
}
return CollectionUtils.filter(new Predicate<String>()
{
public boolean accept(String value)
{
return !value.startsWith("."); Essence
}
}, names);
33 © 2010 Howard Lewis Ship
34. Functional Clojure Collections
Function
Anonymous parameter
function
(filter #(not (.startsWith % ".")) names)
Member
access form
user=> (def names ["fred" "barney" ".hidden" "wilma"])
#=(var user/names)
user=> (filter #(not (.startsWith % ".")) names)
("fred" "barney" "wilma")
user=> (remove #(.startsWith % ".") names)
("fred" "barney" "wilma")
user=>
34 © 2010 Howard Lewis Ship
35. Composing Functions
(filter #(not (.startsWith % ".")) names)
function as
parameter to
function
(defn require-extension [ext]
❝Closure
Oriented
(fn [file-name]
(= ext (last (split-string file-name ".")))))
Programming❞
function as
return value
(filter (require-extension "gz") names)
composing functions
35 © 2010 Howard Lewis Ship
37. Java: Data Encapsulated in
Objects
Stock Stock Stock
ticker: AAPL ticker: MSFT ticker: ORCL
lastTrade: 203.25 lastTrade: 29.12 lastTrade: 21.90
open: 204.50 open: 29.08 open: 21.83
shares: 100 shares: 50 shares: 200
public static List<Double> getOpens(List<Stock> portfolio)
{
List<Double> result = new ArrayList<Double>();
for (Stock stock : portfolio)
{
result.add(stock.getOpen());
}
return result;
}
37 © 2010 Howard Lewis Ship
39. Clojure: Data in Transformable
Collections
:ticker AAPL :ticker MSFT :ticker ORCL
:last-trade 203.25 :last-trade 29.12 :last-trade 21.90
{ :open 204.50 } { :open 29.08 }{ :open 21.83 }
:shares 100 :shares 50 :shares 200
user=> portfolio
[{:ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200}]
user=> (map #(get % :open) portfolio)
(204.50M 29.08M 21.83M)
user=>
39 © 2010 Howard Lewis Ship
40. Clojure: Data in Transformable
Collections
:ticker AAPL :ticker MSFT :ticker ORCL
:last-trade 203.25 :last-trade 29.12 :last-trade 21.90
{ :open 204.50 } { :open 29.08 }{ :open 21.83 }
:shares 100 :shares 50 :shares 200
user=> portfolio
[{:ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200}]
user=> (apply + (map #(* (:last-trade %) (:shares %)) portfolio))
26161.00M
user=> (map #(assoc % :delta (- (% :last-trade) (% :open))) portfolio)
({:delta -1.25M, :ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:delta 0.04M, :ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:delta 0.07M, :ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200})
user=>
40 © 2010 Howard Lewis Ship
41. map
La
zy
f
keywords acts as functions
(:keyword map) == (get map :keyword)
user=> (map :open portfolio)
(204.5 29.08 21.83)
user=> (defn last-trade-value
[stock]
(* (:last-trade stock) (:shares stock)))
#'user/last-trade-value
user=> (map last-trade-value portfolio)
(20325.00M 1456.00M 4380.00M)
user=>
41 © 2010 Howard Lewis Ship
42. Laziness is
a Virtue
user=> (take 20 (iterate inc 1))
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
user=> (take 20 (map * (iterate inc 1) (iterate inc 1)))
(1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400)
42 © 2010 Howard Lewis Ship
43. 43 © 2010 Howard Lewis Ship
44. map
La
zy
f
N seqs ➠ N parameters
user=> (map #(assoc %1 :sort-index %2)
(reverse (sort-by :last-trade portfolio))
(iterate inc 0))
({:sort-index 0, :ticker "AAPL", :last-trade 203.25M, :open 204.50M, :shares 100}
{:sort-index 1, :ticker "MSFT", :last-trade 29.12M, :open 29.08M, :shares 50}
{:sort-index 2, :ticker "ORCL", :last-trade 21.90M, :open 21.83M, :shares 200})
user=>
44 © 2010 Howard Lewis Ship
45. reduce
f
user=> (map #(* (% :last-trade) (% :shares)) portfolio)
(20325.00M 1456.00M 4380.00M)
user=> (reduce + (map #(* (% :last-trade) (% :shares)) portfolio))
26161.00M
user=>
(reduce + (map #(* (% :last-trade) (% :shares)) portfolio))
(reduce + '(20325.00M 1456.00M 4380.00M))
(+ (+ 20325.00M 1456.00M) 4380.00M)
(+ 21781.00M 4380.00M)
26161.00M
45 © 2010 Howard Lewis Ship
46. reduce
f
user=> (def input-string "Clojure is a fascinating language with unique
capabilities and total integration with Java.")
#'user/input-string
user=> (seq input-string)
(C l o j u r e space i s space a space f a s c i n a
t i n g space l a n g u a g e space w i t h space u
n i q u e space c a p a b i l i t i e s space a n d
space t o t a l space i n t e g r a t i o n space w
i t h space J a v a .)
user=> (reduce
(fn [m k] (update-in m [k] #(inc (or % 0))))
Optional initial value {}
(seq input-string))
{space 12, a 12, b 1, C 1, c 2, d 1, e 5, f 1, g 4, h 2, i 11,
J 1, j 1, l 4, . 1, n 7, o 3, p 1, q 1, r 2, s 3, t 8, u 4,
v 1, w 2}
user=>
46 © 2010 Howard Lewis Ship
47. filter / remove
La
zy
f
?
user=> (remove #(< 100 (% :shares)) portfolio)
({:ticker "AAPL", :last-trade 203.25, :open 204.5, :shares 100}
{:ticker "ORCL", :last-trade 21.9, :open 21.83, :shares 57})
user=> (filter #(< 100 (% :shares)) portfolio)
({:ticker "MSFT", :last-trade 29.12, :open 29.08, :shares 125})
user=>
47 © 2010 Howard Lewis Ship
48. for: list comprehension
La
zy
user=> (for [suit [:hearts :clubs :spades :diamonds]
value (range 1 4)]
[suit value])
([:hearts 1] [:hearts 2] [:hearts 3]
[:clubs 1] [:clubs 2] [:clubs 3]
[:spades 1] [:spades 2] [:spades 3]
[:diamonds 1] [:diamonds 2] [:diamonds 3])
user=> (for [x (range 0 4)
y (range 0 (inc x))]
[x y])
([0 0]
[1 0] [1 1]
[2 0] [2 1] [2 2]
[3 0] [3 1] [3 2] [3 3])
user=> (for [x (range 0 9) :when (odd? x)
y (range 1 (inc x))]
[x y])
([1 1]
[3 1] [3 2] [3 3]
[5 1] [5 2] [5 3] [5 4] [5 5]
[7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [7 7])
user=>
48 © 2010 Howard Lewis Ship
49. ❝Somehow the idea of reusability
got attached to object-oriented
programming in the 1980s, and
no amount of evidence to the
contrary seems to be able to
shake it free.❞
Paul Graham
© 2010 Howard Lewis Ship
51. Who Owns the Java Language?
James Gosling Mark Reinhold
51 © 2010 Howard Lewis Ship
52. Not You
52 © 2010 Howard Lewis Ship
53. Control of the Compiler
Source Code
Repl Input Clojure
User Classes Java
Evaluator
Compiler
Clojure
Source Files Java Libraries
JVM
Operating System
53 © 2010 Howard Lewis Ship
56. Short Circuits
&& stops with first false
if (person.isPharaoh() && (if
person.isDead() && (all-true
constructPyramid()) (.isPharaoh person)
{ (.isDead person)
person.bury(); (construct-pyramid))
} (.bury person))
all parameters to function all-true evaluated first
public static boolean allTrue(boolean... inputs)
{
for (boolean input : inputs)
{
if (!input) return false;
}
return true;
}
56 © 2010 Howard Lewis Ship
58. Clojure Macros
short circuit at
first false/nil
Reader
(and a b c d)
Evaluator macro expansion
and macro
Bytecode (let [and__4422__auto__ a]
(if and__4422__auto__
Generation (and b c d)
and__4422__auto__))
Recursively expanded
58 © 2010 Howard Lewis Ship
59. Macros ➠ Special Forms
Code Forms
Macro
Expansion
def if let fn . …
Bytecode
Generation
59 © 2010 Howard Lewis Ship
60. Macros are Special Functions
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
• `(…) — Syntax Quote (allowing replacements)
• and# — Generate a new unique symbol
• ~x — Unquote x
• ~@next — Unquote next and splice in multiple values
60 © 2010 Howard Lewis Ship
61. Macros are Special Functions
(defmacro and
([] true)
([x] x)
(and a b c d)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
•x➠a
• next ➠ '(b c d)
• Inside syntax quote:
• and# ➠ and__4422__auto__
• ~x ➠ a
• ~next ➠ '(b c d)
• (and ~@next) ➠ (and b c d)
61 © 2010 Howard Lewis Ship
62. Simplifying Boilerplate Code
public void testLink()
{
IMocksControl control = EasyMock.createControl();
HttpServletRequest request = control.newMock(HttpServletRequest.class);
HttpServletResponse response = control.newMock(HttpServletResponse.class);
EasyMock.expect(request.getContextPath()).andReturn("/ctx");
EasyMock.expect(response.encodeURL("/ctx/accounts/list")).andReturn("*encoded*");
control.replay();
assertEquals(…, "*encoded*");
control.verify();
}
(deftest test-link
(with-mocks [request HttpServletRequest
response HttpServletResponse]
(:train
(expect .getContextPath request "/ctx")
(expect .encodeURL response "/ctx/accounts/list" "*encoded*"))
(:test
(is (= (link request response list-accounts-with-loop)
"*encoded*")))))
62 © 2010 Howard Lewis Ship
63. Embedded DSLs
(defview root-index
[env]
:html [
:head [
:title [ "Cascade Blog" ]
]
:body [
:h1 [ "Cascade Blog" ]
:html
:ul { :class "recent-postings" } [
(template-for [posting (recent-postings env)]
:li [
(render-link env show-posting (posting :id) (posting :title))
]) :head :body
]
]
])
:title :h1 :ul
"Cascade Blog" "Cascade Blog" (template-for …)
63 © 2010 Howard Lewis Ship
64. Macro Expansions
(defn list-items [coll]
(template
(format "%d items" (count coll))
:ul {:class :item-list} [
(template-for [item coll] :li [item])))
Expand simple Extend Clojure
placeholder to language from
executable code within Clojure
(defn list-items [coll]
(cascade.internal.viewbuilder/combine
(format "%d items" (count coll))
(cascade.dom/element-node :ul {:class :item-list}
(cascade.internal.viewbuilder/combine
(for [item coll]
(cascade.dom/element-node :li nil
(cascade.internal.viewbuilder/combine item)))))))
64 © 2010 Howard Lewis Ship
65. ❝More than anything else, I think it is the
ability of Lisp programs to manipulate
Lisp expressions that sets Lisp apart …
when I hear people complain about Lisp's
parentheses, it sounds to my ears like
someone saying: "I tried one of those
bananas, which you say are so delicious.
The white part was ok, but the yellow
part was very tough and tasted awful."❞
Paul Graham
© 2010 Howard Lewis Ship
66. Wrap Up
66 © 2010 Howard Lewis Ship
67. essence
noun
the intrinsic nature or indispensable quality of
something, esp. something abstract, that
determines its character : conflict is the essence of
drama.
67 © 2010 Howard Lewis Ship
71. Clojure
• 1.1 release: Dec 31 2009
• Simple, regular syntax
• Improves on Lisp: vectors, maps, sets
http://www.clojure.org
• Fully integrates with Java
• Impressive functional & concurrency support
• Many features not covered here
71 © 2010 Howard Lewis Ship
72. Stuart Halloway
Pragmatic Bookshelf
http://pragprog.com/titles/shcloj/programming-clojure
72 © 2010 Howard Lewis Ship
77. Image Credits
© 2007 Jon Fife
http://flickr.com/photos/good-karma/577632972/
© 2007 Casey Marshall
http://www.flickr.com/photos/rsdio/497112391/
© 2009 Howard M. Lewis Ship
http://www.flickr.com/photos/hlship/3603090614/
© 2009 Andrew Baird
http://www.flickr.com/photos/scruffy/3708615414/
© 2008 Miles Sabin
http://www.flickr.com/photos/montpelier/2915114545/
© 2003 A. Lipson
http://www.andrewlipson.com/escher/relativity.html
© 2007 Alan Chia
http://flickr.com/photos/seven13avenue/2080281038/
© 2007 Woodley Wonderworks
http://flickr.com/photos/wwworks/2222523486/
© Randall Munroe
http://xkcd.com/297/
© 2008 Manu Gómez
http://www.flickr.com/photos/manugomi/2884678938/
© 2008 Marcin Wichary
http://www.flickr.com/photos/mwichary/2827326852/
© 2006 Marvin (PA)
http://www.flickr.com/photos/mscolly/145052885/
77 © 2010 Howard Lewis Ship
78. Image Credits
© 2007 John Kannenberg
http://www.flickr.com/photos/jkannenberg/541057337/
© 2006 scott ogilvie
http://www.flickr.com/photos/scottog/100582274/
© 2008 Ariel H.
http://www.flickr.com/photos/fotosrotas/2730733412/
© 2006 John Ryan Brubaker
http://www.flickr.com/photos/subconscience/297682093/
78 © 2010 Howard Lewis Ship