(map Clojure everyday-tasks)

1,829 views

Published on

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

Published in: Technology, News & Politics
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,829
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
64
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • (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 :(

    ×