Advertisement

(map Clojure everyday-tasks)

Apache Spark / Kafka Professional at Value Amplify Consulting
Mar. 21, 2012
Advertisement

More Related Content

Advertisement
Advertisement

(map Clojure everyday-tasks)

  1. Main sponsor (map Clojure everyday-tasks) Jacek Laskowski
  2. About me • Functional apprentice to Clojure • Founder and co-leader of Warszawa JUG • Conference organizer of Javarsovia, Confitura, warsjawa • Member of NetBeans DreamTeam • Blogger of http://JacekLaskowski.pl • Blogger of http://blog.japila.pl • @jaceklaskowski • Member of Apache Software Foundation • IBMer
  3. Why should I care about Clojure? (map Clojure everyday-tasks) Clojure for real-world, day-to-day programming
  4. List comprehension (for [x (range 2) y (range 2)] [x y])
  5. List comprehension (for [x (range 2) y (range 2)] [x y]) user=> ([0 0] [0 1] [1 0] [1 1])
  6. List comprehension function (for [x (range 2) y (range 2)] [x y]) user=> ([0 0] [0 1] [1 0] [1 1])
  7. Persistent data structures • list () • vector [] • map {} • set #{} • They can nest freely • They’re persistent (a.k.a. immutable)
  8. (for [n #{"jacek" "agatka" "iwetka" "patryk" "maksym"}] [n (count n)])
  9. Lists in Clojure 1st item (fn arg1 arg2 ...) 3rd item 2nd item
  10. Function calls in Clojure function name (fn arg1 arg2 ...) function param function param
  11. Reason #1 Functional programming language
  12. Functional language • Functions are first-class citizens • They’re like other values • They can be • passed to a function • returned from a function • HOF = higher-order function
  13. Function definition (fn [args] (body) (defn function-name [args] (body)) #(body)
  14. Function call (function-name arg1 arg2 ...)
  15. Fundamental functions • map - apply a function to a sequence • returns a sequence • reduce - accumulation over a sequence • returns an accumulator • filter - filters items satisfying a predicate • return a sequence
  16. map function Apply a function (map f ‘(1 2 3)) to a sequence and return a sequence in which every item is ‘((f 1) (f 2) (f 3)) transformed by the function Examples: addVat, convertCurrency http://cyrille.martraire.com/2011/03/thinking-functional-programming-with-map-and-fold-in-your-everyday-java/
  17. reduce function (reduce f ‘( 1 2 3 4 )) Accumulate over a sequence and ‘( f ( f ( f 1 2 ) 3 ) 4 ) return the accumulator
  18. Mutation • Persistent references to a mutable state • Var - dynamically rebound on a per- thread basis (thread isolation) • Ref - transactional via Clojure STM • Agent - independent, asynchronous change of individual location • Atom - synchronous, independent state
  19. (def ^:dynamic *b* 5) (defn printb [] *b*) (binding [*b* 10] (printb))
  20. (def ^:dynamic *b* 5) (defn printb [] *b*) (binding [*b* 10] (printb)) user=> 10
  21. explicit about mutation (def ^:dynamic *b* 5) (defn printb [] *b*) (binding [*b* 10] (printb)) user=> 10
  22. (def a (ref 0)) (def b (ref 0)) (alter a inc) ;; java.lang.IllegalStateException: ;; No transaction running (dosync (alter a inc) (alter b inc))
  23. (def a (ref 0)) (def b (ref 0)) (alter a inc) ;; java.lang.IllegalStateException: ;; No transaction running (dosync (alter a inc) (alter b inc)) user=> 1
  24. explicit about mutation (def a (ref 0)) (def b (ref 0)) (alter a inc) ;; java.lang.IllegalStateException: ;; No transaction running (dosync (alter a inc) (alter b inc)) user=> 1
  25. (def c (agent 0)) (send c inc)
  26. (def c (agent 0)) (send c inc) user=> 1
  27. explicit about mutation (def c (agent 0)) (send c inc) user=> 1
  28. (def c (agent 0)) (defn f-agt [v] (Thread/sleep (* v 1000)) (println (Thread/currentThread)) (inc v)) (send c f-agt) ;; (agent-errors c) ;; (restart-agent c 0)
  29. (def atm (atom 0)) (swap! atm inc)
  30. (def atm (atom 0)) (swap! atm inc) user=> 1
  31. explicit about mutation (def atm (atom 0)) (swap! atm inc) user=> 1
  32. Reason #2 Concurrency abstractions
  33. Namespace, Symbols and Vars • Symbol is a name bound to a Var • (def v ...) • Vars can be changed on a per-thread basis • Namespace is a map of symbols to Vars • Namespace is similar to a fully-qualified class name in Java
  34. Clojure REPL
  35. (defn handle-numbers [handler]  (fn []    (doseq [x (iterate inc 0)]       (println (handler x)       (Thread/sleep 1000))))) (defn sample-handler [x] x) (def th (Thread. (handle-numbers sample-handler))) (.start th) (defn sample-handler [x] (- x)) (.stop th) (defn sample-handler [x] x) (def th (Thread. (handle-numbers #'sample-handler))) (.start th)
  36. (import [javax.swing JFrame] [java.awt.event ActionListener]) (def f (JFrame. "A window")) (.setSize f 300 100) (.setVisible f true) (import [javax.swing JButton]) (def b (JButton. "Press me!")) (.add f b) (.pack f) (.addActionListener b (proxy [ActionListener] [] (actionPerformed [evt] (println "I’ve been pressed"))))
  37. Reason #3 Dynamic programming
  38. Values in Clojure • Strings are just instances of java.lang.String user=> (.charAt “abc” 0) • Numbers, characters, nil, true, false, and keywords evaluate to themselves user=> (Character/isLetter c)
  39. Regular expressions • #"pattern" - java.util.regex.Pattern • (re-seq re s) lazy seq of matches of re in s • (re-find m) the next regex match • (re-matches re s) returns the match • (re-matcher re s) gives j.u.regex.Matcher • (re-groups m) returns the groups
  40. user=> (def ptrn #"[0-9]+") #'user/ptrn user=> (class ptrn) java.util.regex.Pattern user=> (re-seq ptrn "abc 123 a 2 2 1") ("123" "2" "2" "1")
  41. Java interop • (.instanceMember instance args*) • (.instanceMember Classname args*) • (Classname/staticMethod args*) • Classname/staticField
  42. Java interop macros • (.. instance-expr member+) • (doto instance-expr (instanceMethodName-symbol args*)*) • (Classname. args*)
  43. Reason #4 Easy Java interop
  44. clojure.main • Run scripts from the command line • java -jar clojure.jar your-script.clj args*
  45. AOT compilation • Clojure compiles all code you load on-the- fly into JVM bytecode • Ahead-of-time (AOT) = before on-the-fly at runtime • Target of (compile) is namespace • Each file, fn, and gen-class give new .class
  46. :gen-class sample (ns helloworld Classname  
  47. :gen-class sample (ns helloworld   (:gen-class)) Execute AOT  
  48. :gen-class sample (ns helloworld   (:gen-class))   (defn -main [& args] the main function
  49. :gen-class sample (ns helloworld   (:gen-class))   (defn -main [& args]   (println "Hello world!")) the main’s body
  50. :gen-class sample (ns helloworld   (:gen-class))   (defn -main [& args]   (println "Hello world!"))
  51. AOT in Practice • lein new [project-name] • Add :main to project.clj • lein uberjar • java -jar [project-name-ver-standalone.jar]
  52. Java EE web apps with Clojure (Maven and Leiningen are there, too!) http://blog.japila.pl/2012/03/java-ee-web-apps-with-clojure-maven-and-leiningen-are-there-too/
  53. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo
  54. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo $ lein new my-webapp-demo-clj
  55. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo $ lein new my-webapp-demo-clj (ns my-webapp-demo-clj.core   (:gen-class    :methods [[hello [String] String]])) (defn -hello   [this s]   (str "Hello, " s))
  56. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo $ lein new my-webapp-demo-clj public String hello(String) (ns my-webapp-demo-clj.core   (:gen-class    :methods [[hello [String] String]])) (defn -hello   [this s]   (str "Hello, " s))
  57. (defproject my-webapp-demo-clj "1.0.0-SNAPSHOT"   :description "FIXME: write description"   :dependencies [[org.clojure/clojure "1.3.0"]]   :aot :all)
  58. (defproject my-webapp-demo-clj "1.0.0-SNAPSHOT"   :description "FIXME: write description"   :dependencies [[org.clojure/clojure "1.3.0"]]   :aot :all) $ lein install
  59. (defproject my-webapp-demo-clj "1.0.0-SNAPSHOT"   :description "FIXME: write description"   :dependencies [[org.clojure/clojure "1.3.0"]]   :aot :all) $ lein install <dependency>   <groupId>my-webapp-demo-clj</groupId>   <artifactId>my-webapp-demo-clj</artifactId>   <version>1.0.0-SNAPSHOT</version> </dependency>
  60. <html> <body> <h2>Hello World!</h2> </body> <p> <%= new my_webapp_demo_clj.core().hello("Jacek") %> </p> </html>
  61. <html> <body> <h2>Hello World!</h2> </body> <p> <%= new my_webapp_demo_clj.core().hello("Jacek") %> </p> </html> $ mvn package
  62. <html> <body> <h2>Hello World!</h2> </body> <p> <%= new my_webapp_demo_clj.core().hello("Jacek") %> </p> </html> $ mvn package
  63. Reason #5 Easy Java interop both ways
  64. Leiningen lein - a project automation tool
  65. Starting a project • lein new [project-name] • Edit project.clj (mainly deps) • Also plugin configuration, e.g. :main for run (soon explained)
  66. Custom project setup defproject in project.clj customized
  67. Dependencies • lein deps • lein search [library]
  68. clojars Maven repository for Clojure projects http://clojars.org/
  69. Ongoing development • lein repl • lein eclipse • lein midje (“formerly” lein test) • lein run • lein jar • Some require custom setup...
  70. Unit testing • clojure.test namespace • the is macro (is (= 5 (+ 2 2)) "Crazy arithmetic") • the are macro • the deftest macro (deftest addition (is (= 4 (+ 2 2))) (is (= 7 (+ 3 4)))) • (run-tests & namespaces)
  71. lein test [ns] Runs project tests, optionally only from a ns
  72. src/hi/core.clj (ns hi.core) (defn hi ([] "Hi!") ([name] (str "Hi " name "!")))
  73. lein test $ lein test Copying 1 file to /Users/jacek/sandbox/hi/lib Testing hi.test.core FAIL in (replace-me) (core.clj:6) No tests have been written. expected: false actual: false Ran 1 tests containing 1 assertions. 1 failures, 0 errors.
  74. test/hi/test/core.clj (ns hi.test.core (:use [hi.core]) (:use [clojure.test])) (deftest hi-simple-test (is (= (hi) "Hi!")) (is (= (hi "Clojure") "Hi Clojure!")))
  75. lein test $ lein test Testing hi.test.core Ran 1 tests containing 2 assertions. 0 failures, 0 errors.
  76. Modern unit testing • Midje - a TDD library for Clojure that supports top-down ('mockish') TDD • https://github.com/marick/Midje • midje.sweet namespace • fact macro • (fact "one plus one is two" (+ 1 1) => 2)
  77. Midje and Leiningen • lein plugin install lein-midje 1.0.8 • :dev-dependencies [[lein-midje "1.0.8"] [midje "1.3.1"]] • lein midje • lein midje --lazytest
  78. TDD with Midje #0 • :repositories ["stuart" "http://stuartsierra.com/maven2"] • :dev-dependencies [com.stuartsierra/lazytest "1.2.3"]
  79. TDD with Midje #1 $ lein midje --lazytest ====================================== At #<Date Tue Feb 21 13:07:52 CET 2012> Reloading librarian-clojure.run, librarian-clojure.repl, librarian-clojure.test.core, librarian-clojure.core, librarian-clojure.books, librarian-clojure.db FAIL at (core.clj:10) Expected: 2 Actual: 3 FAIL at (core.clj:10) Expected: 2 Actual: 3 FAILURE: 1 fact was not confirmed. (But 1 was.) Done. ====================================== At #<Date Tue Feb 21 13:08:11 CET 2012> Reloading librarian-clojure.test.core All claimed facts (2) have been confirmed. Done.
  80. TDD with Midje #2 • (fact "doubles odd numbers"   (my-func 3) => 6) • (fact "triples even numbers"   (my-func 4) => 12) • A solution? http://www.lispplusplus.com/2012/02/tdd-in-midje-in-nutshell.html
  81. TDD with Midje #3 • Which solution do you prefer? • (defn my-func [n]   (if (odd? n)     (* 2 n)     (* 3 n)) • (defn my-func [n]   (let [multiplier (if (odd? n) 2 3)]     (* multiplier n)) • Monitor lein terminal
  82. Reason #6 Familiar-looking project tools
  83. Ring Clojure HTTP server applications https://github.com/mmcgrana/ring
  84. Compojure A concise web framework for Clojure https://github.com/weavejester/compojure
  85. Ring up jacek:~/oss/librarian-clojure $ lein ring server :ring {:handler librarian-clojure.core/app}
  86. Reason #7 Web application libraries
  87. Multimethods • Runtime dynamic dispatch • (defmulti say-count count) (defmethod say-count 0 [_] "Zero") (defmethod say-count 1 [_] "One") (defmethod say-count :default [_] "A Bunch") • (say-count [1 2 3]) http://blog.fogus.me/2011/10/14/why-clojure-doesnt-need-invokedynamic-but-it-might-be-nice/
  88. user=> (defmulti say-class class) user=> (defmethod say-class (class {}) [_] "A map") user=> (say-class {}) "A map" user=> (say-class []) java.lang.IllegalArgumentException: No method in multimethod 'say-class' for dispatch value: class clojure.lang.PersistentVector (NO_SOURCE_FILE:0) user=> (defmethod say-class (class []) [_] "A vector") user=> (say-class []) "A vector"
  89. Reason #8 Multi-level dispatch
  90. Are you still uncertain? There’s more, but... time flies by so fast :(

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
Advertisement