http://www.philandstuff.com/slides/2014/intro-to-clojure.html
About ⅓ presentation, ⅔ practical, 2 hours
First hour: language fundamentals
Second hour: project
Type Ctrl-<SPACE>
then type "instarepl"
press <ENTER>
Basic expression is an operator applied to zero or more arguments:
(operator arg1 arg2 ...)
Sometimes known as an s-expression or sexp.
Python:
sorted([9,1,6,4])
Clojure:
(sort [9 1 6 4])
Ruby:
"".empty? "foo".empty?
Clojure:
(empty? "") (empty? "foo")
Ruby:
[1,2,3].concat( [4,5,6] )
Clojure:
(concat [1 2 3] [4 5 6])
Ruby:
1 + 2 1 + 2 + 3 + 4
Clojure:
(+ 1 2) (+ 1 2 3 4)
1.upto(10).each do |x| puts 2*x end
(for [i (range 1 10)]
(* 2 i))
def add1(n) n + 1 end
(defn add1 [n] (+ n 1))
(defroutes my-app (GET "/" [] "Welcome!") (GET "/profile/:user" [user] (str "Hello, " user "!")) (POST "/profile/:user" [user comment] (add-to-comments user comment)) (route/not-found "<h1>Page not found</h1>"))
(go-loop [[response-ch request] (<! http-channel)] (condp = (:method request) :get (>! response-ch "Hello world!") :post (do (>! missile-handler :launch) (>! response-ch "Missile launch sequence initiated."))))
nil
1 1/2 1234N 0.3M
"strings"
\c \h \a \r \s \!
:keyword 'symbol
[:a :b :c]
(def v [:a :b :c]) (first v) ;=> :a (last v) ;=> :c (nth v 1) ;=> :b
(def v [:a :b :c]) (conj v :d) ;=> [:a :b :c :d] (assoc v 1 42) ;=> [:a 42 :c] (pop v) ;=> [:a :b] v ;=> [:a :b :c] -- unchanged!
{:foo 1, :bar 2}
(def m {:few 2, :some 4}) (get m :few) ;=> 2 (get m :many) ;=> nil
#{:a :b :c :d}
(def colours #{:red :yellow :blue}) (conj colours :green) ;=> #{:red :blue :green :yellow} (disj colours :red) ;=> #{:blue yellow}
(fn [x y] (if (< x y) y x))
((fn [x y] (if (< x y) y x)) 12 56) ;=> 56
(def my-max (fn [x y] (if (< x y) y x))) (my-max 12 56) ;=> 56
(defn my-max [x y] (if (< x y) y x)) (my-max 12 56) ;=> 56
(let [triple (fn [x] (+ x x x)) x 5] (triple x)) ;;=> 15 (triple 10) ;; unable to resolve symbol: triple
You may find the Clojure Grimoire useful:
Classes, objects, locks, threads, variables, inheritance, encapsulation, dispatch…
Identity, time, values, state, place, perception, visibility…
Objects are not thread safe by default
We have to work hard to achieve safety
Lost updates:
[:jam]
[:jam]
[:jam :peanut-butter]
[:jam :nutella]
Immutable values and pure functions are safe by default
But: not all things we want to talk about are immutable values or pure functions
(atom init-val)
(deref a)
or @a
(swap! a f x y z)
(f @a x y z)
atomically
(def a (atom [:jam]))
(swap! a conj :peanut-butter)
(swap! a conj :nutella)
(ref init-val)
(deref r)
or @r
(dosync ...)
Within a transaction:
(ensure r)
(alter r f x y z)
r
with (f @r x y z)
(ref-set r x)
r
to x
If a transaction fails due to a concurrent modification, it automatically retries.
(def player (ref #{})) (def monster (ref #{:sword :gold :shield})) (defn steal-from [thief victim] (dosync (let [chosen-item (first (shuffle (ensure victim)))] (alter victim disj chosen-item) (alter thief conj chosen-item)))) (steal-from player monster)
(def world (atom {:player #{} :monster #{}})) (defn steal-from [world thief victim] (let [chosen-item (first (shuffle victim))] (-> world (update-in [victim] disj chosen-item) (update-in [thief] conj chosen-item)))) (swap! world steal-from :player :monster)
Agents: uncoordinated, asynchronous
core.async: CSP-style (ie golang-style), channels and queues
Vars: thread-local storage
;; import a class (at the repl) (import 'java.net.URI) ;; new URI("http://icanhazip.com") (def uri (URI. "http://icanhazip.com")) ;; call a static method (def uri2 (URI/create "http://icanhazip.com")) ;; call a method (.getScheme uri) ;;=> "http" ;; Java null maps to Clojure nil (.getFragment uri) ;;=> nil
(def l (ArrayList.)) (.add l 1) (.add l 3) (.add l "foobar") ;;=> l is now [1 3 "foobar"]
(def l (doto (ArrayList.) (.add 1) (.add 3) (.add "foobar")))
;; List's addAll() method takes a java.util.Collection: (.addAll l [:more :data :from :clojure]) ;; now l is [1 3 "foobar" :more :data :from :clojure]
(def l (doto (ArrayList.) (.addAll [1 3 "foobar"]))) (map str l) ;;=> ("1" "3" "foobar") (filter number? l) ;;=> (1 3)
This is all very neat, but how do I actually get something done?
Do you already have this installed? If not, go to http://leiningen.org/
git clone git@github.com:WWCLondon/snake.git
Pick a team name, and:
git checkout -b <team-name>
Open snake/project.clj
in LightTable:
Rich Hickey, "Are we there yet? "http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey
ClojureScript Koans: http://clojurescriptkoans.com/
London Clojurians: http://londonclojurians.org/
ClojureBridge: http://www.clojurebridge.org/
(all announced on london-clojurians mailing list)