際際滷

際際滷Share a Scribd company logo
Programowanie funkcjonalne
funkcyjnie z Clojure praktycznie
      O budowaniu wsp坦bie甜nej aplikacji gra鍖cznej




                                                          Jacek Laskowski
                                                                   jacek@japila.pl
                                                     http://www.JacekLaskowski.pl
                                                                       wersja 1.0, 12.05.2011
Ja...cek Laskowski
   Entuzjasta Java EE, OSGi, SCA oraz programowania funkcyjnego (Clojure)

   Zao甜yciel i lider Warszawa JUG

   Organizator Con鍖tura 2011

   Czonek zespou NetBeans DreamTeam

   Blogger na http://JacekLaskowski.pl

   Blogger na http://blog.japila.pl

   Twittuje jako @jaceklaskowski

   Czonek zespo坦w Apache Geronimo i Apache OpenEJB

   Specjalista produkt坦w IBM WebSphere w IBM Polska
konferencja spoecznoci javowej w Polsce

     Con鍖tura 2011
            http://con鍖tura.pl
            11 czerwiec
               Warszawa
         (poprzednio Javarsovia)
infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie
店r坦da inspiracji
   Programming Concurrency on the JVM: Mastering
    Synchronization, STM, and Actors
    http://www.jaceklaskowski.pl/wiki/
    Book_review:_Programming_Concurrency_on_the_JVM


   Java Concurrency in Practice
    http://jcip.net
$ java -version
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-10M3326)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02-334, mixed mode)

$ clj
user=> (clojure-version)
"1.3.0-alpha6"
user=> ; przestrze nazewnicza (ang. namespace) w Clojure
user=> ; mapa symboli na ich odpowiedniki pene - odnoniki i klasy
user=> (ns gui)
nil
gui=>
gui=> (def nazwa-konferencji "InfoShare")
#'gui/nazwa-konferencji
gui=> (import javax.swing.JFrame)
javax.swing.JFrame
gui=> (use 'clojure.contrib.swing-utils)
nil
gui=> (ns-interns 'gui)
{nazwa-konferencji #'gui/nazwa-konferencji}
gui=> (import (javax.swing JFrame JButton JTextField JOptionPane))
javax.swing.JOptionPane
gui=> (import (java.awt GridLayout))
java.awt.GridLayout
gui=> (use '[clojure.contrib.swing-utils :only (add-action-listener)])
nil
gui=> (JFrame. nazwa-konferencji)
#<JFrame javax.swing.JFrame
[frame1,0,22,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Info
Share,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,ro
otPane=javax.swing.JRootPane[,
0,0,0x0,invalid,layout=javax.swing.JRootPane
$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,鍖ags=16777673,
maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabl
ed=true]>
gui=> (def f (JFrame. nazwa-konferencji))
#'gui/f
gui=> (doto f
         .pack
         .show)
#<JFrame javax.swing.JFrame
[frame2,0,22,128x37,layout=java.awt.BorderLayout,title=InfoShare,resiz
able,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=java
x.swing.JRootPane[,0,22,128x15,layout=javax.swing.JRootPane
$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,鍖ags=16777673,
maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabl
ed=true]>
infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie
gui=> (.setSize f 600 300)
nil
infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie
gui=> (def word-input-鍖eld (JTextField. 30))
#'gui/word-input-鍖eld
gui=> (defn create-enter-handler [input-鍖eld]
 (fn enter-handler
   [event]
   (let [w (.. input-鍖eld getText)
        msg (format "<html>Input: <b>%s</b></html>" w)]
     (do
      (JOptionPane/showMessageDialog nil msg "Information"
JOptionPane/INFORMATION_MESSAGE)
      (.. input-鍖eld (requestFocusInWindow))
      (.. input-鍖eld (selectAll))))))
#'gui/create-enter-handler
gui=> (add-action-listener word-input-鍖eld (create-enter-handler
word-input-鍖eld))
#<Object$ActionListener$46793e3a clojure.contrib.swing_utils.proxy
$java.lang.Object$ActionListener$46793e3a@50152643>
gui=> (.add f word-input-鍖eld)
#<JTextField javax.swing.JTextField[...]>
gui=> (.pack f)
nil
infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie
infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie
Programming Concurrency on the JVM, page 18
Programming Concurrency on the JVM, page 22
Model pamici Java
 Memory barrier
   Clojure jest jzykiem funkcyjnym

   Clojure hoduje funkcjom czystym (ang. pure functions)

   To甜samo (ang. identity) = logiczny byt, symbol

   Stan (ang. state) = warto

   Czas (ang. time) = migawka

   Clojure oddziela to甜samo od stanu = upraszcza wsp坦bie甜no
安壊沿坦恢庄艶甜稼看
      vs
wielowtkowo
http://twitpic.com/4wdy02
Sztandarowy program wsp坦bie甜ny
           w Clojure
            ants.clj
    http://paste.lisp.org/display/81878/raw
$ wc ants.clj
   319 1323      9727 ants.clj

$ grep Thread ants.clj
   (. Thread (sleep ant-sleep-ms))
 (. Thread (sleep animation-sleep-ms))
 (. Thread (sleep evap-sleep-ms))
$ clj
Clojure 1.3.0-alpha6
user=> (load-鍖le "ants.clj")
nil
user=> (def ants (setup))
#'user/ants
user=> (send-off animator animation)
#<Agent@12dfbabd: nil>
user=> (dorun (map #(send-off % behave) ants))
nil
Clojure a stan
       4 rodzaje referencji (odwoa do pamici) w Clojure

         Vars - dynamiczna referencja do zmiennej wartoci (per wtek)

         Refs - transakcyjny Var dla wielu wtk坦w

         Agents - asynchroniczny i niezale甜ny

         Atoms - synchroniczny i niezale甜ny stan
STAN
STAN
$ grep agent ants.clj
  "create an ant at the location, returning an ant agent on the location"
       (agent loc))))
  "places initial food and ants, returns seq of ant agents"
;ant agent functions
;an ant agent tracks the location of an ant, and controls the behavior of
  "the main function for the ant agent"
      (send-off *agent* #'behave))
(def animator (agent nil))
    (send-off *agent* #'animation))
(def evaporator (agent nil))
    (send-off *agent* #'evaporation))
$ grep ref ants.clj
;world is a 2d vector of refs to cells
              (apply vector (map (fn [_] (ref (struct cell 0 0)))
                 (rank-by (comp #(if (:home %) 1 0) deref) places)
                 (rank-by (comp :pher deref) places))]
                        (rank-by (comp :food deref) places)
                        (rank-by (comp :pher deref) places))]
         (.setPreferredSize (new Dimension
$ grep atom ants.clj
user=> (doc future)
-------------------------
clojure.core/future
([& body])
Macro
 Takes a body of expressions and yields a future object that will
  invoke the body in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet 鍖nished, calls to deref/@ will block.
user=> (source future-cancel)
(defn future-cancel
 "Cancels the future, if possible."
 {:added "1.1"
  :static true}
 [^java.util.concurrent.Future f] (.cancel f true))
user=> (doc pmap)
-------------------------
clojure.core/pmap
([f coll] [f coll & colls])
  Like map, except f is applied in parallel. Semi-lazy in that the
  parallel computation stays ahead of the consumption, but doesn't
  realize the entire result unless required. Only useful for
  computationally intensive functions where the time of f dominates
  the coordination overhead.
user=> (doc pcalls)
-------------------------
clojure.core/pcalls
([& fns])
  Executes the no-arg fns in parallel, returning a lazy sequence of
  their values
clojure.lang.Agent
user=> (source agent)
(defn agent
...
   ([state & options]
     (let [a (new clojure.lang.Agent state)
           opts (apply hash-map options)]
       (setup-reference a options)
       (when (:error-handler opts)
         (.setErrorHandler a (:error-handler opts)))
       (.setErrorMode a (or (:error-mode opts)
                       (if (:error-handler opts) :continue :fail)))
       a)))
$ javap -classpath clojure.jar clojure.lang.Agent
Compiled from "Agent.java"
public class clojure.lang.Agent extends clojure.lang.ARef{
   java.util.concurrent.atomic.AtomicReference aq;
   public static 鍖nal java.util.concurrent.ExecutorService
pooledExecutor;
   public static 鍖nal java.util.concurrent.ExecutorService soloExecutor;
   public java.lang.Object dispatch(clojure.lang.IFn, clojure.lang.ISeq,
boolean);
   static void dispatchAction(clojure.lang.Agent$Action);
   void enqueue(clojure.lang.Agent$Action);
   public int getQueueCount();
   public static int releasePendingSends();
   ...
clojure.lang.Atom
user=> (source atom)
(defn atom
...
   ([x] (new clojure.lang.Atom x))
   ([x & options] (setup-reference (atom x) options)))
clojure.lang.Ref
user=> (source ref)
(defn ref
...
   ([x] (new clojure.lang.Ref x))
   ([x & options]
    (let [r ^clojure.lang.Ref (setup-reference (ref x) options)
          opts (apply hash-map options)]
     (when (:max-history opts)
       (.setMaxHistory r (:max-history opts)))
     (when (:min-history opts)
       (.setMinHistory r (:min-history opts)))
     r)))
Programowanie funkcjonalne
funkcyjnie z Clojure praktycznie
      O budowaniu wsp坦bie甜nej aplikacji gra鍖cznej




                                                          Jacek Laskowski
                                                                   jacek@japila.pl
                                                     http://www.JacekLaskowski.pl
                                                                       wersja 1.0, 12.05.2011

More Related Content

infoShare 2011 - Jacek Laskowski - Programowanie Funkcjonalne Funkcyjnie z Clojure Praktycznie

  • 1. Programowanie funkcjonalne funkcyjnie z Clojure praktycznie O budowaniu wsp坦bie甜nej aplikacji gra鍖cznej Jacek Laskowski jacek@japila.pl http://www.JacekLaskowski.pl wersja 1.0, 12.05.2011
  • 2. Ja...cek Laskowski Entuzjasta Java EE, OSGi, SCA oraz programowania funkcyjnego (Clojure) Zao甜yciel i lider Warszawa JUG Organizator Con鍖tura 2011 Czonek zespou NetBeans DreamTeam Blogger na http://JacekLaskowski.pl Blogger na http://blog.japila.pl Twittuje jako @jaceklaskowski Czonek zespo坦w Apache Geronimo i Apache OpenEJB Specjalista produkt坦w IBM WebSphere w IBM Polska
  • 3. konferencja spoecznoci javowej w Polsce Con鍖tura 2011 http://con鍖tura.pl 11 czerwiec Warszawa (poprzednio Javarsovia)
  • 5. 店r坦da inspiracji Programming Concurrency on the JVM: Mastering Synchronization, STM, and Actors http://www.jaceklaskowski.pl/wiki/ Book_review:_Programming_Concurrency_on_the_JVM Java Concurrency in Practice http://jcip.net
  • 6. $ java -version java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-10M3326) Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02-334, mixed mode) $ clj user=> (clojure-version) "1.3.0-alpha6"
  • 7. user=> ; przestrze nazewnicza (ang. namespace) w Clojure user=> ; mapa symboli na ich odpowiedniki pene - odnoniki i klasy user=> (ns gui) nil gui=> gui=> (def nazwa-konferencji "InfoShare") #'gui/nazwa-konferencji gui=> (import javax.swing.JFrame) javax.swing.JFrame gui=> (use 'clojure.contrib.swing-utils) nil gui=> (ns-interns 'gui) {nazwa-konferencji #'gui/nazwa-konferencji}
  • 8. gui=> (import (javax.swing JFrame JButton JTextField JOptionPane)) javax.swing.JOptionPane gui=> (import (java.awt GridLayout)) java.awt.GridLayout gui=> (use '[clojure.contrib.swing-utils :only (add-action-listener)]) nil
  • 9. gui=> (JFrame. nazwa-konferencji) #<JFrame javax.swing.JFrame [frame1,0,22,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Info Share,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,ro otPane=javax.swing.JRootPane[, 0,0,0x0,invalid,layout=javax.swing.JRootPane $RootLayout,alignmentX=0.0,alignmentY=0.0,border=,鍖ags=16777673, maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabl ed=true]>
  • 10. gui=> (def f (JFrame. nazwa-konferencji)) #'gui/f gui=> (doto f .pack .show) #<JFrame javax.swing.JFrame [frame2,0,22,128x37,layout=java.awt.BorderLayout,title=InfoShare,resiz able,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=java x.swing.JRootPane[,0,22,128x15,layout=javax.swing.JRootPane $RootLayout,alignmentX=0.0,alignmentY=0.0,border=,鍖ags=16777673, maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabl ed=true]>
  • 12. gui=> (.setSize f 600 300) nil
  • 14. gui=> (def word-input-鍖eld (JTextField. 30)) #'gui/word-input-鍖eld gui=> (defn create-enter-handler [input-鍖eld] (fn enter-handler [event] (let [w (.. input-鍖eld getText) msg (format "<html>Input: <b>%s</b></html>" w)] (do (JOptionPane/showMessageDialog nil msg "Information" JOptionPane/INFORMATION_MESSAGE) (.. input-鍖eld (requestFocusInWindow)) (.. input-鍖eld (selectAll)))))) #'gui/create-enter-handler
  • 15. gui=> (add-action-listener word-input-鍖eld (create-enter-handler word-input-鍖eld)) #<Object$ActionListener$46793e3a clojure.contrib.swing_utils.proxy $java.lang.Object$ActionListener$46793e3a@50152643> gui=> (.add f word-input-鍖eld) #<JTextField javax.swing.JTextField[...]> gui=> (.pack f) nil
  • 18. Programming Concurrency on the JVM, page 18
  • 19. Programming Concurrency on the JVM, page 22
  • 20. Model pamici Java Memory barrier
  • 21. Clojure jest jzykiem funkcyjnym Clojure hoduje funkcjom czystym (ang. pure functions) To甜samo (ang. identity) = logiczny byt, symbol Stan (ang. state) = warto Czas (ang. time) = migawka Clojure oddziela to甜samo od stanu = upraszcza wsp坦bie甜no
  • 24. Sztandarowy program wsp坦bie甜ny w Clojure ants.clj http://paste.lisp.org/display/81878/raw
  • 25. $ wc ants.clj 319 1323 9727 ants.clj $ grep Thread ants.clj (. Thread (sleep ant-sleep-ms)) (. Thread (sleep animation-sleep-ms)) (. Thread (sleep evap-sleep-ms))
  • 26. $ clj Clojure 1.3.0-alpha6 user=> (load-鍖le "ants.clj") nil
  • 27. user=> (def ants (setup)) #'user/ants user=> (send-off animator animation) #<Agent@12dfbabd: nil>
  • 28. user=> (dorun (map #(send-off % behave) ants)) nil
  • 29. Clojure a stan 4 rodzaje referencji (odwoa do pamici) w Clojure Vars - dynamiczna referencja do zmiennej wartoci (per wtek) Refs - transakcyjny Var dla wielu wtk坦w Agents - asynchroniczny i niezale甜ny Atoms - synchroniczny i niezale甜ny stan
  • 30. STAN
  • 31. STAN
  • 32. $ grep agent ants.clj "create an ant at the location, returning an ant agent on the location" (agent loc)))) "places initial food and ants, returns seq of ant agents" ;ant agent functions ;an ant agent tracks the location of an ant, and controls the behavior of "the main function for the ant agent" (send-off *agent* #'behave)) (def animator (agent nil)) (send-off *agent* #'animation)) (def evaporator (agent nil)) (send-off *agent* #'evaporation))
  • 33. $ grep ref ants.clj ;world is a 2d vector of refs to cells (apply vector (map (fn [_] (ref (struct cell 0 0))) (rank-by (comp #(if (:home %) 1 0) deref) places) (rank-by (comp :pher deref) places))] (rank-by (comp :food deref) places) (rank-by (comp :pher deref) places))] (.setPreferredSize (new Dimension
  • 34. $ grep atom ants.clj
  • 35. user=> (doc future) ------------------------- clojure.core/future ([& body]) Macro Takes a body of expressions and yields a future object that will invoke the body in another thread, and will cache the result and return it on all subsequent calls to deref/@. If the computation has not yet 鍖nished, calls to deref/@ will block.
  • 36. user=> (source future-cancel) (defn future-cancel "Cancels the future, if possible." {:added "1.1" :static true} [^java.util.concurrent.Future f] (.cancel f true))
  • 37. user=> (doc pmap) ------------------------- clojure.core/pmap ([f coll] [f coll & colls]) Like map, except f is applied in parallel. Semi-lazy in that the parallel computation stays ahead of the consumption, but doesn't realize the entire result unless required. Only useful for computationally intensive functions where the time of f dominates the coordination overhead. user=> (doc pcalls) ------------------------- clojure.core/pcalls ([& fns]) Executes the no-arg fns in parallel, returning a lazy sequence of their values
  • 38. clojure.lang.Agent user=> (source agent) (defn agent ... ([state & options] (let [a (new clojure.lang.Agent state) opts (apply hash-map options)] (setup-reference a options) (when (:error-handler opts) (.setErrorHandler a (:error-handler opts))) (.setErrorMode a (or (:error-mode opts) (if (:error-handler opts) :continue :fail))) a)))
  • 39. $ javap -classpath clojure.jar clojure.lang.Agent Compiled from "Agent.java" public class clojure.lang.Agent extends clojure.lang.ARef{ java.util.concurrent.atomic.AtomicReference aq; public static 鍖nal java.util.concurrent.ExecutorService pooledExecutor; public static 鍖nal java.util.concurrent.ExecutorService soloExecutor; public java.lang.Object dispatch(clojure.lang.IFn, clojure.lang.ISeq, boolean); static void dispatchAction(clojure.lang.Agent$Action); void enqueue(clojure.lang.Agent$Action); public int getQueueCount(); public static int releasePendingSends(); ...
  • 40. clojure.lang.Atom user=> (source atom) (defn atom ... ([x] (new clojure.lang.Atom x)) ([x & options] (setup-reference (atom x) options)))
  • 41. clojure.lang.Ref user=> (source ref) (defn ref ... ([x] (new clojure.lang.Ref x)) ([x & options] (let [r ^clojure.lang.Ref (setup-reference (ref x) options) opts (apply hash-map options)] (when (:max-history opts) (.setMaxHistory r (:max-history opts))) (when (:min-history opts) (.setMinHistory r (:min-history opts))) r)))
  • 42. Programowanie funkcjonalne funkcyjnie z Clojure praktycznie O budowaniu wsp坦bie甜nej aplikacji gra鍖cznej Jacek Laskowski jacek@japila.pl http://www.JacekLaskowski.pl wersja 1.0, 12.05.2011