Contenu connexe
Similaire à Codemash-Clojure.pdf (20)
Plus de Howard Lewis Ship (10)
Codemash-Clojure.pdf
- 4. 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. 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))
14 © 2010 Howard Lewis Ship
- 15. Java: Complex Structure
int result = a * b - start + offset;
Higher precendence, then left to right: ((a * b) - start) + offset
+
(+
- offset (-
(* a b)
* start start))
offset)
a b
15 © 2010 Howard Lewis Ship
- 17. 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
17 © 2010 Howard Lewis Ship
- 18. REPL and Compilation
Source Code
Repl Input Clojure
User Classes Java
Evaluator
Compiler
Clojure
Source Files Java Libraries
JVM
Operating System
18 © 2010 Howard Lewis Ship
- 19. Clojure Literals
user=> 42
42
user=> "A Clojure String"
"A Clojure String"
user=> space
space
user=> A
A
user=> nil
nil
user=> :balance
:balance
user=> true
true
user=> false
false
19 © 2010 Howard Lewis Ship
- 20. Clojure Literals
user=> 5
5
user=> 5.001
5.001
user=> 22/7
22/7
user=> (* 2 22/7)
44/7
user=> (* 100000 100000 100000)
1000000000000000
user=> (+ 5. 0.000000000000000001)
5.0
user=> (+ 5.0M 0.000000000000000001M)
5.000000000000000001M
20 © 2010 Howard Lewis Ship
- 21. Java Interop: Function Calls
(.method-name receiver arguments…)
(.setNamespaceAware factory true)
(.. factory newSAXParser (parse src handler))
(.parse (.newSAXParser factory) src handler)
factory.newSAXParser().parse(src, handler);
21 © 2010 Howard Lewis Ship
- 22. 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
22 © 2010 Howard Lewis Ship
- 23. 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]
user=> (v 1)
:larry
vector is a
function of
its indexes
23 © 2010 Howard Lewis Ship
- 24. 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" map is a
user=> (m :last-name) function of
"Lewis Ship"
user=> (assoc m :company "TWD")
its keys
{:company "TWD", :last-name "Lewis Ship", :first-name "Howard"}
user=> m
{:last-name "Lewis Ship", :first-name "Howard"}
user=> (:first-name m)
"Howard"
user=> (:ssn m)
nil
Keywords are
functions, too!
24 © 2010 Howard Lewis Ship
- 25. 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 set is a
user=> (s "Howard") function of
"Howard" its elements
user=> (s "Rhys")
nil
user=> (conj s "Howard")
#{"Howard" "Jim" "Molly" "Suzanne"}
user=> (conj s "Scott")
#{"Howard" "Jim" "Molly" "Suzanne" "Scott"}
25 © 2010 Howard Lewis Ship
- 27. My First Program
No it
10 X = 1 doesn't!
20 PRINT X
30 X = X + 1
40 GOTO 20
27 © 2010 Howard Lewis Ship
- 32. Functional Programming in Java
public void saveOrUpdate(final Employee employee)
{
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
throws HibernateException,SQLException
{
session.saveOrUpdate(employee);
return null;
}
};
hibernateTemplate.execute(callback);
}
Outer function controls the
SwingUtilities.invokeLater(new Runnable() context:
{
public void run() • Thread
{ • Exception handling
progressBar.setValue(progressBar.getValue() + 1);
} • Parameters
});
32 © 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 :open portfolio)
(204.50M 29.08M 21.83M)
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=>
39 © 2010 Howard Lewis Ship
- 40. map
La
z y
f
:open acts as a function
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=>
40 © 2010 Howard Lewis Ship
- 41. 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)
41 © 2010 Howard Lewis Ship
- 42. 42 © 2010 Howard Lewis Ship
- 43. map
La
z y
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=>
43 © 2010 Howard Lewis Ship
- 44. 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
44 © 2010 Howard Lewis Ship
- 45. 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=>
45 © 2010 Howard Lewis Ship
- 46. filter / remove
La
z y
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=>
46 © 2010 Howard Lewis Ship
- 47. for: list comprehension
La
z y
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=>
47 © 2010 Howard Lewis Ship
- 48. !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
- 50. Who Owns the Java Language?
James Gosling Mark Reinhold
50 © 2010 Howard Lewis Ship
- 51. Not You
51 © 2010 Howard Lewis Ship
- 52. Control of the Compiler
Source Code
Repl Input Clojure
User Classes Java
Evaluator
Compiler
Clojure
Source Files Java Libraries
JVM
Operating System
52 © 2010 Howard Lewis Ship
- 55. 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
55 © 2010 Howard Lewis Ship
- 56. Macros # Special Forms
Code Forms
Macro
Expansion
def if let fn . …
Bytecode
Generation
56 © 2010 Howard Lewis Ship
- 57. 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
57 © 2010 Howard Lewis Ship
- 58. 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)
58 © 2010 Howard Lewis Ship
- 59. 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*")))))
59 © 2010 Howard Lewis Ship
- 60. 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 …)
60 © 2010 Howard Lewis Ship
- 61. 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)))))))
61 © 2010 Howard Lewis Ship
- 62. !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
- 63. Wrap Up
63 © 2010 Howard Lewis Ship
- 64. 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
64 © 2010 Howard Lewis Ship
- 65. Stuart Halloway
Pragmatic Bookshelf
http://pragprog.com/titles/shcloj/programming-clojure
65 © 2010 Howard Lewis Ship
- 70. 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/
70 © 2010 Howard Lewis Ship
- 71. 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/
71 © 2010 Howard Lewis Ship