Clojure: Practical functional approach on JVM

download Clojure: Practical functional approach on JVM

If you can't read please download the document

Transcript of Clojure: Practical functional approach on JVM

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