clojure: practical functional approach on jvm
TRANSCRIPT
ClojurePractical Functional Approach on JVM
Sun Ning2011.11.28
Agenda
Introduction to Clojure
Real World Clojure
Clojure People
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
Functional Programming
Avoiding Mutable State
Functions as First-Class Values
Lambdas and Closures
Higher-Order Functions
Side-Effect-Free Functions
Recursion
Lazy vs. Eager Evaluation
Declarative vs. Imperative Programming
Functional Programming
Avoiding Mutable StateBetter concurrency (no need for locking)
Persistent data structure
zs = xs + ys
Functional Programming
Functions as First-Class Values
Lambdas and Closures
Higher-Order Functions
;; integer as first class value(def a 10)
;; function as first class value(def b (fn [x] (+ x a)))
;; anonymous function#(+ a %)
;; function that generate a closure(def c (fn [x] #(+ x %)))
;; high order function (function as parameter)(def d (fn [f x] (f x a)))
Functional Programming
Side-Effect-Free Functions
;; function that free of side effect(defn f [x] (+ x 1000))
;; function with side effect(defn f [x] (println (str logging: x= x)) (+ x 1000))
;; I/O operations are side effect(defn dump [writer data] (.write writer data))
Functional Programming
RecursionRecursive Looping
public int sumAll(int n) { int i = 1, s = 0; while(i 0){ return n + sumAll(n-1); } else { return 0; }}
(defn sum-all [n] (if (> n 0) (+ n (sum-all (dec n))) 0))
(defn sum-all2 [n s] (if (> n 0) (recur (dec n) (+ n s)) s))(defn sum-all [n] (sum-all2 n 0))
java.lang.StackOverflowError
Tail recursion
Functional Programming
Lazy Evaluation
;; define data(def data [1 2 3 4 5])
;; a function with side effect(defn side-effect-inc [i] (println i) (inc i))
;; create lazy sequence with map(def lazy-data (map side-effect-inc data))
;; consume first 2 items for lazy sequence(take 2 lazy-data)
(123452 3)
(take 5 (range))
(take 5 (repeat a))
Functional Programming
Declarative ProgrammingDSL
(cd "/home/login" (path "/home/login/bin" (run "clojure")))
(cd "/home/login" (path "/home/login/bin" (env "JAVA_OPTS" "-XMaxPermSize=128m" (run "ant compile"))))
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
Syntax
Symbol: user/m
Character: \a
Integer: 1 2 3
String: hello
Keyword: :world
Boolean: true
Null: nil
Collections
Vector: [1 2 3]
List: (1 2 3)
Set: #{1 2 3}
Map: {:a 1 :b 2}
(def a 12)
(def b tomcat)
(def c (fn [x y] (+ x y)))
(def c #(+ %1 %2))
(defn c [x y] (+ x y))
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
State management
Coordinated vs. Independent StateCoordinated updates cant just take one identity into accountthey have to manage the states of several interdependent identities to ensure that they are all updated at the same time and that none are left out.
Synchronous vs. Asynchronous Updates
State management
Ref - Synchronous, Coordinated
Atom Synchronous, Independent
Agent Asynchronous
Vars Thread local values
State management
;;refs and STM(def a (ref 0))(def b (ref 1))
(dosync (alter a inc) (alter b + @a))
@a@b
;;atoms(def a (atom 0))(def b (atom 1))
(swap! a inc)(swap! b + @a)
@a@b
;;agents(def a (agent 0))(def b (agent 1))
(send a inc)(send b + @a)
;;thread local binding(def a 0)(def b 1)
(binding [a 100] (+ b a))
a
STM
Multiple version concurrent controlEach transaction gets its own view of the data that its interested in.
Each transaction merrily chugs along making changes to in-transaction values only.
Examine the refs against the modification target for conflicts.
Commit changes or Retry
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
Macro
Write code that writes code
Macro
(defmacro cd "change current directory" [path & cmd] `(str "cd " ~path "; " ~@cmd))
(defmacro run "simply run a command" [cmd] `(str ~cmd "; "))
Macro
(cd /home/nsun (run rm -rf ./*))cd /home/nsun; rm -rf ./*;
(macroexpand '(cd "/home/nsum" (run "rm -rf ./*")))(clojure.core/str "cd " "/home/nsum" "; " (run "rm -rf ./*"))
Introduction to Clojure
Functional Programming
Lisp Syntax
State Management
Macro
Java Interop
Java Interop Java for Clojure
(import java.util.Date)(def now (Date.))(.getTime now)(System/currentTimeMillis)
Java Interop - Clojure->Java
(ns gen-class-test.core (:gen-class :state value :init init :constructors {[String] []} :methods [[printValue [String] void] ^{:static true} [version [] String]]))
(defn version [] "1.0")
(defn -init [name] [[] (atom {:name name})])
(defn -printValue [this prefix] (println (str prefix @(.value this))))
Real World Clojurewhere functional programming landed
Real World Clojure
Network programming
Web development
Databases
Network Programming
Aleph network programming framework (HTTP/TCP/UDP)
Lamina Abstraction of Queue
Gloss Abstraction of bytes protocol
Based on Netty
Aleph
(defcodec dummy-codec (finite-frame :int24 (string :utf8)))
(defn echo-handler [ch client-info] (receive-all ch #(do (println %) (enqueue ch %))))
(start-tcp-server echo-handler {:port 1234, :frame dummy-codec})
Gloss codec
Lamina queue
Aleph
Web Development
Web handler abstractionRing (Similar to WSGI, Rack)
Web frameworksCompojure
Noir
Ring
(defn app [req] {:status 200 :headers {"Content-Type" "text/html"} :body "Hello World from Ring"})
MiddlewareMiddlewareMiddlewareHandlerMiddleware
Compojure framework
(defroutes default-routes (GET "/rage/:id" [] get-rage) (GET "/rages/:channel" [] get-rages))
(defn get-rage [req] (let [id (:id (:params req))] (json-response (get-data id))))
(defroutes default-routes (GET "/rage/:id" [] get-rage) (GET "/rages/:channel" [] get-rages))
Clojure JDBC DDL
;; database config(def db {:classname "org.hsqldb.jdbc.JDBCDriver" :subprotocol "hsqldb" :subname "testdb" :user "SA" :password ""})
(defn create-db [] (jdbc/with-connection db (jdbc/create-table table-name [:name "VARCHAR(32)" "PRIMARY KEY"] [:submitter "VARCHAR(32)"] [:title "VARCHAR(512)"])))
Clojure JDBC DML
(jdbc/with-connection db (jdbc/with-query-results results [(str "select * from " (name table-name))] (into [] results)))
Clojure PeopleMeet clojure hackers on github
@richhickey
Creator of clojure
Presentations:Simple made Easy
Hammock-driven-development
@fogus
Clojure and ClojureScript core developers
Author of The Joy of Clojure
http://blog.fogus.me/
@nathanmarz
Leader engineer of backtype (acquired by twitter)
Creator ofStorm (realtime computation framework)
Cascalog (clojure query language on hadoop)
@mmcgrana
Heroku engineer
Author of Ring spec
Author ofClj-redis
Clj-http
Clj-stacktrace
...
@technomancy
Heroku engineer
Emacs hackerAuthor of emacs-starter-kit
Author of leiningen (clojure build tool)
@Raynes
17 years old Clojure guy
co-developer of Clojail
tryclj.com
Clojure community and me
Many more
@ztellman (Aleph, Lamina, Gloss)
@ibdknox (Noir, Korma, I Will Build Your Prototype)
@weavejester (Compojure, Ring)
@ghoseb (Planet Clojure)
@cemerick (O'Reilly Clojure Programming)
@stuarthalloway (Pragmatic Programming Clojure)
@stuartsierra (Clojure core developer, Apress Practical Clojure)
Q&A
Thanks