http://www.lvh.io/ClojureIntro/
https://www.github.com/lvh/ClojureIntro
Fellow of the Python Software Foundation Staff member of PyCon US
A lot of content
(apply modern-lisp @jvm)
Official JS target, semi-mature CLR target, various experimental targets
(f a b c)
just a different spelling for:
f(a, b, c)
Originally written for AI John McCarthy 1957 Interpreters, high-level metaprogramming, garbage collection, dynamic programming, functional programming, programming with recursive functions…
Lots of reasons:
How long does it take to try something?
(Partial) static typing
Software transactional memory
Asynchronous programming
Logic programming
Most other languages are the same or worse
Lisp is a ball of mud
$LANG is a shiny diamond
Usually not considered a compliment But hopefully I’ve piqued your interest
“85% functional”
Not just in Clojure; semantically, mutable values are lies
12 Jan 1991, 18 Mar 2002
How many dates?
E.g. collections
For some reason we don’t accept this for compound values
{3, 5}, {3, 5, 7}
How many sets?
Imperative, single-threaded programming!
No concept of time or transitions
“No man can cross the same river twice.”
– Heraclitus, ~500 BC
The river doesn’t stop existing just because nobody is around to call it a river…
E.g. logs, source control
What if they destroyed data?
They would be totally useless
Keeping old versions around is cheap!
Bit-partitioned hash tries
Encapsulation doesn’t fix this!
Indirect reference to immutable value
Doesn’t affect readers; not affected by readers
Deep similarity!
(def n (atom 1)) (swap! n inc) ;; => 2 (swap! n * 10) ;; => 20
Transactions: atomicity, consistency, isolation (not durability) Since Clojure 1.0
(def n (ref "xyzzy")) @n ;; => "xyzzy" (dosync (prn @n)) ;; xyzzy
(def n (ref 0)) (alter n inc) ;; IllegalStateException ;; No transaction running ... @n ;; => 0 (dosync (alter n inc)) @n ;; => 1
(defn transfer [amount from to] (dosync (alter from - amount) (alter to + amount)))
(def counter (ref 0)) (defn slow-inc! [alter-fn counter] (dosync (Thread/sleep 100) (alter-fn counter inc))) (defn bombard-counter! [n f counter] (apply pcalls (repeat n #(f counter))))
(dosync (ref-set counter 0)) (time (doall (bombard-counter! 20 (partial slow-inc! alter) counter))) ;; => (1 2 4 3 5 6 13 12 9 8 7 11 10 15 17 14 20 18 19 16) ;; "Elapsed time: 2025.646 msecs" ;; 20 incs * 100 ms = 2000 ms...
(dosync (ref-set counter 0)) (time (doall (bombard-counter! 20 (partial slow-inc! commute) counter))) ;; => (3 6 1 1 7 1 1 8 8 8 8 8 10 14 15 15 19 15 15 19) ;; "Elapsed time: 305.23 msecs" ;; Without delay: virtually instant, so 3 txn attempts
Pretty intricate
Implementation has a number of clever tricks…
Not complaining about Steegmans or his class He’s a great guy, hates giving that class in Java as much as we hated getting it in Java But @Raw makes me sad
Why not locks?
Manual memory management
versus
GC and lifetime analysis
One atom, usually with a map, to hold state:
(def app-state (atom {:user-name "lvh" :todo-items ["Take out trash" "Present Clojure intro"] :done-items #{"Make slides"}}))
I don’t know for sure, but I have some hypotheses:
Real answer is probably all of the above & more :-)
(1.7, beta)
Just monoids in the category of endofunctors!
My spell checker is not convinced these are words
(map f coll)
((f x) for all x in coll)
(map inc [1 2 3]) ;; => (2 3 4)
(filter f coll)
(all of the x in coll, if (f x))
(filter even? [1 2 3]) ;; => (2)
(reduce f coll)
(accumulate over coll with f)
(reduce + [1 2 3 4]) ;; => 10
We kept implementing map, reduce, etc.
Extract the essence of map, reduce…
(map f)
vs.
(map f coll)
(map f)
vs.
(partial map f)
(Examples adapted from Rich Hickey’s Strange Loop talk)
;; Build concrete collections (into airplane process-bags pallets) ;; Build a lazy sequence (sequence process-bags pallets) ;; "Reduce" a collection (transduce (comp process-bags (map weigh)) + pallets) ;; core.async channels (chan 1 process-bags)
(def xform (comp (partial map inc) (partial filter odd?) (partial map #(* 3 %))))
(xform [1 2 3])
(comp (mapcat unbundle-pallet) (take-while (complement ticking?)) (filter (complement smells-like-food?)) (map label-heavy-items) (take max-plane-capacity))
Many basic “language features” are macros:
defn, and, cond…
(Just like Racket)
Which m?
C# 4.0 apparently supports multimethods
Not just type of x, but the value of x.m
x still picks the m!
(Smalltalk parlance)
x ← m(a, b, c)
Routing logic: f(x)
Icecap example?
Going back is painful ;-)
Bad type systems