Introducing Clojure
Elegant Functional Programming on JVM
Mafinar Rashid Khan
Product Manager
Panacea Systems Limited
@mafinar
About Mafinar
- Fan of "The Flash"
- Makes finance systems, micro-frameworks, GIS
- Works with Python 2 and Clojure[Script]
- Can be sarcastic
- Doesn't like Java or OOP or Design Patterns
- Loves JVM
- Hates JavaScript
- Knows Kung-fu
An general purpose , pragmative, dynamic, functional variant of Lisp on top of JVM with concurrency and power in mind...
...Elegance and Simplicity Made Easy...
Why should one care?
LISP
Power and Elegance...
- Simple in design, elegance in bloodline
- Functional Programming at its finest
- Extreme power, extensible even at syntax level
- Mother of all DSL
- Good for grokking AI
- If you can think of anything, in any way, Lisp can do it
- Futuristic features... since 1950s.
Stuff from legends...
- "the greatest single programming language ever designed" - Alan Kay
- "Greenspun's Tenth Rule of Programming: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp." - Philip Greenspun
- "Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people." - Matz
- Lisp isn't a language, it's a building material." - Alan Kay
- “Within a couple weeks of learning Lisp I found programming in any other language unbearably constraining.” - Paul Graham
- “Lisp is a language for doing what you've been told is impossible.” - Kent Pitman
Eric Raymond
“Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.”
Edsger Dijkstra
“Lisp has jokingly been called "the most intelligent way to misuse a computer". I think that description is a great compliment because it transmits the full flavor of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.”
JVM
Do I really need to say anything here?
Solid. Performant. Secure. Industry. Enterprise. Innovative. Omnipresent. Concurrent. Parallel. Big Data.
Let's not get into who uses it or what got created with JVM?
Unless you want to give me the whole session or more?
"We were not out to win over the Lisp programmers; we were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp." - Guy Steele
Clojure drags them the other half
LISP + JVM = Clojure
Clojure goodies...
- Simple and powerful syntax
- Ability to create awesome DSL
- Combination of purity and pragmatism
- Entire Java ecosystem available
- Making concurrency easier
- Extremely productive and performant
- Great community
Who's using it?
- Akamai
- BackType
- CircleCI
- CITI
- Cognitect
- Deutsche Bank
- eBay
- Groupon
- HelpShift
- Heroku
- Netflix
- Panacea Systems
- Prismatic
- PuppetLabs
- SoundCloud
- Spotify
- TeraData
- ThoughtWorks
- Tulos Capital
- 2 Sigma
- Unbound
- uSwitch
- Walmart Labs
- World Singles
- ZenDesk
Clojure brings the power of Lisp into the glory of JVM...
Making Java[script] fun(ctional), awesomer and less boring
Bringing Lisp on a Java meet-up...
Sword on a Gun-fight?
Gun on a Sword Fight?
Tank on either?
So How do I do this???
Keep it Simple, Stupid!!!
My to-do list...
Discuss theories of functional programmingTeach Clojure, along with its macro features, concurrency constructs, transducers, monads, lambda calculusLogical/Relational programming while at itRecreate ADA and FORTRAN with Clojure via live-codingDiscuss theory of relativityDisplay round-house kicks- Whet your appetite
- Talking some FP for OOP guys
- Discuss some simple ideas on how Clojure makes you think
All I can do is make you interested and present you some ideas... and let you in on how Clojurists think
You decide upon it...
Let's learn the language first...
In one slide...
Clojure in one slide...
- () for LIST, [] for Vectors, {:key value} for maps
- true is True, false is False, nil is Null
- You think in Lists (Lisp = LISt Processing, remember?)
- First element of a Lisp is an operation, the remaining are its arguments
- Arguments can be lists too, or vector, keyword, number etc.
- Parentheses all the way...
Congratulations, you know Clojure (and probably all other Lisps)
Source code isn't really the point here.. the concepts are.
Immutability
Functional Programming
Concurrency & Parallelism
Interoperability
Take 1. Immutability
Nothing changes...
People never change, they just become more of what they are
- Count Lestat, Interview with the Vampire
Immutability is...
Basically forgetting about assignments and those little boxes holding values, you play pillow passing with values, values that never change.
But it demands a special data structure to ensure fast operation on immutable data.
One word for you...
Bit Partitioned Vector Trie
(def brown [0 1 2 3 4 5 6 7 8])
(def blue (assoc brown 5 'beef))
(def brown [0 1 2 3 4 5])
(def blue (pop brown))
(def green (pop brown))
Take 2: Functional Programming
Functions as First Class Citizens
You focus on VERBs, not NOUNs
So, it's eat(cat, rat), NOT cat.eat(rat)
(eat cat rat) in Lisp parlance... ;-)
...some pointers
- Lambda Calculus
- Higher Order Functions
- Closure
- Pure Functions
Lambda Calculus
- Fancy Name for function?
- Remember f(x) = x + 1; therefore f(10) = ?
- (fn [x] (+ x 1))
- #(* % %)
- (defn add-a-with-b #(+ %1 %2))
- I promise, I'm not swearing...
- yet.
Higher Order Functions
- Functions can take functions in
- Functions can return function bodies
- Also called Functor, Functional Form etc
- map, reduce, filter etc.
(map square (range 100))
(->> (range 1 100)
(comp #(square %) #(cube %))
(apply +))
Closures
- A data structure storing a function
- A function body that has its local variable snapshots remembered per call
- That's how Clojure got its name?
(defn pow [n]
(fn [x] (apply * (repeat n x))))
(def square (pow 2))
(def qubic (pow 3))
A pure function is a function that always returns the same output for same input
Useful for memoization, but not always pragmatic (database? random number? printing?)
Then there is partial function, laziness, sequence abstraction...
Take 3: Concurrency and Paralellism
Doing multiple things in style
So what are these things? Concurrency and Parallelism?
Concurrency is managing more than one task at the same time.
When you are texting and driving, you're being concurrent. (DON'T by the way)...
But you don't do them at the same time, you "interleave"
Paralellism is actually doing two tasks simultaneously.
Erm... writing with both hands? Can you?
If a task takes two hands, and you have two hands, you cannot do more than two tasks paralelly.
Oh, and having a friend write a text for you while you drive is distribution.
A special case of paralellism?
Know your enemies:
Shared State
Clojure and Concurrency
- Futures and Promises
- Atom
- Ref
- Var
- Agents
- core.async
Futures dispatch a computation on a different thread
Cheapest way to attain multithreadedness
(def what-is-the-answer-to-life (future
(println "[Future] started computation")
(Thread/sleep 3000) ;; running for 3 seconds
(println "[Future] completed computation")
42))
(println "[Main] created future")
(Thread/sleep 1000)
(println "[Main] do other things while waiting for the answer")
(println "[Main] get the answer")
(println "[Main] the result" @what-is-the-answer-to-life)
Promise is like its English meaning, something that promises a delivery sometime in future
(def p (promise)) ;=#'user/p
(realized? p) ;=false
(deliver p "as-promised")
(realized? p) ;=true
@p ;="as-promised"
State Management
- Refs are for Coordinated Synchronous access to "Many Identities".
- Atoms are for Uncoordinated synchronous access to a single Identity.
- Agents are for Uncoordinated asynchronous access to a single Identity.
- Vars are for thread local isolated identities with a shared default value.
Atom
Primary Operations: swap! and reset!
(def click-count (atom 0))
(defn counting-component []
[:div
"The atom " [:code "click-count"] " has value: "
@click-count ". "
[:input {:type "button" :value "Click me!"
:on-click #(swap! click-count inc)}]])
Ref - STM
- Software Transactional Memory
- Similar to ACID (From Database Theory) sans D
- All actions in a "ref" are atomic, either one or none
- Automatic retry on failures
- Operations: ref-set, alter, commute
(def accounts
[(ref 0)
(ref 10)
(ref 20)
(ref 30)])
(defn transfer [src-account
dest-account
amount]
(dosync
(alter dest-account + amount)
(alter src-account - amount)))
(map deref accounts)
;=> (5 5 20 30)
I haven't ever used Agent, so not discussing it here.
Now the most awesome... core.async
Let's do asynchronous programming...
I don't like statically typed language and I have Java anonymous classes. JavaScript is cool so I shall use JavaScript.
-- NOT me.
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}),
{'pk':CustomPKFactory});
p_client.open(function(err, p_client) {
p_client.dropDatabase(function(err, done) {
p_client.createCollection('test_custom_key', function(err, collection) {
collection.insert({'a':1}, function(err, docs) {
collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {
cursor.toArray(function(err, items) {
test.assertEquals(1, items.length);
// Let's close the db
p_client.close();
});
});
});
});
});
});
... Now I have two problems... intertwined ;-)
core.async's Hadouken...
Here's how you do...
- Create a channel
- Whenever something happens, pass it on >!
- Subscribers of the channel will immediately get it <!
- They know what to do with it.
- Channels can be blocking or unblocking
- Reactive Programming FTW!!!
(defn upper-caser
[in]
(let [out (chan)]
(go (while true (>! out (clojure.string/upper-case (<! in)))))
out))
(defn reverser
[in]
(let [out (chan)]
(go (while true (>! out (clojure.string/reverse (<! in)))))
out))
(defn printer
[in]
(go (while true (println (<! in)))))
(def in-chan (chan))
(def upper-caser-out (upper-caser in-chan))
(def reverser-out (reverser upper-caser-out))
(printer reverser-out)
(>!! in-chan "redrum")
; => MURDER
(>!! in-chan "repaid")
; => DIAPER
Credits: Clojure for the Brave and True
Take 4: Interoperability
Communicating with the hosts
Because you don't want to miss out on the decades of Java.
This is actually simple...
(Integer/parseInt "0")
;; Integer.parseInt("0")
(.toUpperCase "hello")
;; "hello".toUpperCase()
(.. System
(getProperties)
(get "os.name"))
;; System.getProperties().get("os.name")
(doto (new java.util.HashMap)
(.put "a" 1)
(.put "b" 2))
; HashMap hm = new HashMap();
; hm.put("a", 1);
; hm.put("b", 1);
Advanced Stuff...
Programming by Wishful Thoughts...
Top-Down Approach
- Think how you want to see your solution
- Type the outcome
- Start Implementing...
- Remember, you can bend your syntax at will
(def-html page [title, body]
(title title)
(body (div (map employee-snippet employee-list))))
(def-snippet employee-snippet [e]
(table :data (employees) :class "alternate-row"))
(def-form employee-form
(html-form :map-with (get-employee-structure)
:on-click create-employee!))
(defn employee-list
(sql
(select "employee" [:first-name :last-name] :order-by "age")))
(defn create-employee!
(sql!
(create "employee" [:first-name :last-name] ["Mafinar" "Khan"]))
Program your Programming Language
Macro
- Much like templates, but for programming language
- Abstract away a snippet into your own liking
- True power of Lisp
;; UNLESS <YES> <NO> = generate_code("if (!_LOGIC_) { _YES_ } else { _NO_ }")
(defmacro unless [pred a b] `(if (not ~pred) ~a ~b))
Behold the Mighty Leiningen
A Leiningen Project File
A List of Resources and Talks?
... look ahead!
There you go...
- Official site: http://clojure.org/
- Community Doc site: http://clojuredocs.org
- The best programming book ever: http://www.braveclojure.com/
- Do listen to these: https://changelog.com/rich-hickeys-greatest-hits/
- Awesome Clojure: https://github.com/razum2um/awesome-clojure
Shameless Plug...
This book I am trying to write...
While you're at it-
Introducing Clojure[Script]
By Mafinar Khan
Introducing Clojure[Script]
My slides on the JUGBD 5.0 on Clojure
- 2,182