Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

(map Clojure everyday-tasks)

2,003 views

Published on

Presentation on Clojure from the 33rd degree conference in Krakow, Poland, in March 2012.

Published in: Technology, News & Politics
  • Be the first to comment

(map Clojure everyday-tasks)

  1. 1. Main sponsor(map Clojure everyday-tasks) Jacek Laskowski
  2. 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. 3. Why should I care about Clojure? (map Clojure everyday-tasks)Clojure for real-world, day-to-day programming
  4. 4. List comprehension(for [x (range 2) y (range 2)] [x y])
  5. 5. List comprehension(for [x (range 2) y (range 2)] [x y])user=> ([0 0] [0 1] [1 0] [1 1])
  6. 6. List comprehensionfunction(for [x (range 2) y (range 2)] [x y])user=> ([0 0] [0 1] [1 0] [1 1])
  7. 7. Persistent data structures• list ()• vector []• map {}• set #{}• They can nest freely• They’re persistent (a.k.a. immutable)
  8. 8. (for [n #{"jacek" "agatka" "iwetka" "patryk" "maksym"}] [n (count n)])
  9. 9. Lists in Clojure1st item(fn arg1 arg2 ...) 3rd item 2nd item
  10. 10. Function calls in Clojurefunction name (fn arg1 arg2 ...) function param function param
  11. 11. Reason #1Functional programming language
  12. 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. 13. Function definition (fn [args] (body) (defn function-name [args] (body)) #(body)
  14. 14. Function call(function-name arg1 arg2 ...)
  15. 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. 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 functionExamples: addVat, convertCurrencyhttp://cyrille.martraire.com/2011/03/thinking-functional-programming-with-map-and-fold-in-your-everyday-java/
  17. 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. 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. 19. (def ^:dynamic *b* 5)(defn printb [] *b*)(binding [*b* 10] (printb))
  20. 20. (def ^:dynamic *b* 5)(defn printb [] *b*)(binding [*b* 10] (printb))user=> 10
  21. 21. explicit about mutation(def ^:dynamic *b* 5)(defn printb [] *b*)(binding [*b* 10] (printb))user=> 10
  22. 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. 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. 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. 25. (def c (agent 0))(send c inc)
  26. 26. (def c (agent 0))(send c inc)user=> 1
  27. 27. explicit about mutation (def c (agent 0)) (send c inc) user=> 1
  28. 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. 29. (def atm (atom 0))(swap! atm inc)
  30. 30. (def atm (atom 0))(swap! atm inc)user=> 1
  31. 31. explicit about mutation(def atm (atom 0))(swap! atm inc)user=> 1
  32. 32. Reason #2Concurrency abstractions
  33. 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. 34. Clojure REPL
  35. 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. 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. 37. Reason #3Dynamic programming
  38. 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. 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. 40. user=> (def ptrn #"[0-9]+")#user/ptrnuser=> (class ptrn)java.util.regex.Patternuser=> (re-seq ptrn "abc 123 a 2 2 1")("123" "2" "2" "1")
  41. 41. Java interop• (.instanceMember instance args*)• (.instanceMember Classname args*)• (Classname/staticMethod args*)• Classname/staticField
  42. 42. Java interop macros• (.. instance-expr member+)• (doto instance-expr (instanceMethodName-symbol args*)*)• (Classname. args*)
  43. 43. Reason #4Easy Java interop
  44. 44. clojure.main• Run scripts from the command line• java -jar clojure.jar your-script.clj args*
  45. 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. 46. :gen-class sample (ns helloworld Classname 
  47. 47. :gen-class sample (ns helloworld   (:gen-class)) Execute AOT 
  48. 48. :gen-class sample (ns helloworld   (:gen-class))  (defn -main [& args] the main function
  49. 49. :gen-class sample (ns helloworld   (:gen-class))  (defn -main [& args]   (println "Hello world!")) the main’s body
  50. 50. :gen-class sample (ns helloworld   (:gen-class))  (defn -main [& args]   (println "Hello world!"))
  51. 51. AOT in Practice• lein new [project-name]• Add :main to project.clj• lein uberjar• java -jar [project-name-ver-standalone.jar]
  52. 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. 53. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo
  54. 54. $ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp-demo$ lein new my-webapp-demo-clj
  55. 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. 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. 57. (defproject my-webapp-demo-clj "1.0.0-SNAPSHOT"  :description "FIXME: write description"  :dependencies [[org.clojure/clojure "1.3.0"]]  :aot :all)
  58. 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. 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. 60. <html><body><h2>Hello World!</h2></body><p> <%= new my_webapp_demo_clj.core().hello("Jacek") %></p></html>
  61. 61. <html><body><h2>Hello World!</h2></body><p> <%= new my_webapp_demo_clj.core().hello("Jacek") %></p></html>$ mvn package
  62. 62. <html><body><h2>Hello World!</h2></body><p> <%= new my_webapp_demo_clj.core().hello("Jacek") %></p></html>$ mvn package
  63. 63. Reason #5Easy Java interop both ways
  64. 64. Leiningenlein - a project automation tool
  65. 65. Starting a project• lein new [project-name] • Edit project.clj (mainly deps) • Also plugin configuration, e.g. :main for run (soon explained)
  66. 66. Custom project setup defproject in project.clj customized
  67. 67. Dependencies• lein deps• lein search [library]
  68. 68. clojarsMaven repository for Clojure projects http://clojars.org/
  69. 69. Ongoing development• lein repl• lein eclipse• lein midje (“formerly” lein test)• lein run• lein jar• Some require custom setup...
  70. 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. 71. lein test [ns]Runs project tests, optionally only from a ns
  72. 72. src/hi/core.clj(ns hi.core)(defn hi ([] "Hi!") ([name] (str "Hi " name "!")))
  73. 73. lein test$ lein testCopying 1 file to /Users/jacek/sandbox/hi/libTesting hi.test.coreFAIL in (replace-me) (core.clj:6)No tests have been written.expected: false actual: falseRan 1 tests containing 1 assertions.1 failures, 0 errors.
  74. 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. 75. lein test$ lein testTesting hi.test.coreRan 1 tests containing 2 assertions.0 failures, 0 errors.
  76. 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. 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. 78. TDD with Midje #0• :repositories ["stuart" "http://stuartsierra.com/maven2"]• :dev-dependencies [com.stuartsierra/lazytest "1.2.3"]
  79. 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.dbFAIL at (core.clj:10) Expected: 2 Actual: 3FAIL at (core.clj:10) Expected: 2 Actual: 3FAILURE: 1 fact was not confirmed. (But 1 was.)Done.======================================At #<Date Tue Feb 21 13:08:11 CET 2012>Reloading librarian-clojure.test.coreAll claimed facts (2) have been confirmed.Done.
  80. 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. 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. 82. Reason #6Familiar-looking project tools
  83. 83. RingClojure HTTP server applicationshttps://github.com/mmcgrana/ring
  84. 84. Compojure A concise web framework for Clojurehttps://github.com/weavejester/compojure
  85. 85. Ring upjacek:~/oss/librarian-clojure$ lein ring server:ring {:handler librarian-clojure.core/app}
  86. 86. Reason #7Web application libraries
  87. 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. 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 multimethodsay-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. 89. Reason #8Multi-level dispatch
  90. 90. Are you still uncertain? There’s more, but...time flies by so fast :(

×