$30 off During Our Annual Pro Sale. View Details »

Clojure for PHP Developers

Clojure for PHP Developers

My introduction to Clojure from PHP Tek 12 #tek12

Ian Barber

May 25, 2012
Tweet

More Decks by Ian Barber

Other Decks in Technology

Transcript

  1. ian barber - [email protected] - @ianbarber
    CLOJURE
    FOR PHP DEVELOPERS

    View Slide

  2. WHAT IS
    CLOJURE AND
    WHAT IS IT
    GOOD FOR?

    View Slide

  3. INSTALLING CLOJURE
    mac osx
    $ brew install rlwrap leiningen
    debian / ubtuntu
    $ apt-get install leiningen
    windows
    https://github.com/technomancy/leiningen
    http://dev.clojure.org/display/doc/Getting+Started

    View Slide

  4. SEQUENCES
    CONCURRENCY WITH STM
    REPL
    $ lein repl
    REPL started;
    user=>

    View Slide

  5. READ
    EVALUATE
    PRINT
    LOOP

    View Slide

  6. (ns boids.core
    (:use [quil.core]))
    (def wwidth 646) ; Map width
    (def wheight 400) ; Map height
    (def avoid-dist 20) ; Stay this far apart
    (def col-dist 35) ; Avoid columns
    (def col-size 30) ; Column size
    (def infl-dist 100) ; Boids influence
    (def boid-count 50) ; How many boids
    (def boid-diam 5) ; Size of a boid
    (def max-speed 6) ; Boid max speed
    https://github.com/ianbarber/Boids

    View Slide

  7. /* Head towards the rest of the boids */
    function attract($x, $y, $boids) {
    $cboids = closest($x, $y, $boids, 100);
    $boid_count = count($boids) == 0 ?
    count($boids) : 1;
    $sum_x = $sum_y = 0;
    foreach ($cboids as $boid) {
    $sum_x += $boid['x'];
    $sum_y += $boid['y'];
    }
    $x_average = $sum_x / $boid_count;
    $y_average = $sum_y / $boid_count;
    return array(
    ($x_average - $x),
    ($y_average - $y) );
    }

    View Slide

  8. /* Head towards the rest of the boids */
    defn attract(x, y, boids) {
    cboids = closest(x, y, boids, 100);
    boid_count = count(boids) == 0 ?
    count(boids) : 1;
    sum_x = sum_y = 0;
    foreach (cboids as boid) {
    sum_x += boid['x'];
    sum_y += boid['y'];
    }
    x_average = sum_x / boid_count;
    y_average = sum_y / boid_count;
    return array(
    (x_average - x),
    (y_average - y) );
    }

    View Slide

  9. /* Head towards the rest of the boids */
    (defn attract [x y boids]
    cboids = (closest x y boids 100)
    boid_count = (count boids) == 0 ?
    (count boids) : 1
    sum_x = sum_y = 0
    foreach (cboids as boid) {
    sum_x += (:x boid)
    sum_y += (:y boid)
    }
    x_average = (/ sum_x boid_count)
    y_average = (/ sum_y boid_count)
    [ (- x_average x) (- y_average y) ]
    )

    View Slide

  10. (defn attract
    "Head towards the rest of the boids"
    [x y boids]
    (let [
    cboids (closest x y boids 100)
    boid_count (if (= 0 (count boids))
    0 (count boids))
    [sum_x sum_y] foreach (cboids as boid){
    sum_x += (:x boid)
    sum_y += (:y boid)
    }
    x_average] (/ sum_x boid_count)
    y_average (/ sum_y boid_count)
    ]
    [ (- x_average x) (- y_average y) ]
    )

    View Slide

  11. (let [
    [sum_x sum_y] (reduce
    (fn [[sum_x sum_y] boid]
    [(+ sum_x (:x boid))
    (+ sum_y (:y boid))]
    [0 0]
    cboids)
    ])
    list($sum_x, $sum_y) =
    array_reduce($cboids,
    function($boid, $sum) {
    return array(
    $sum[0] + $boid['x'],
    $sum[1] + $boid['y']);
    }, array(0,0));

    View Slide

  12. UNIT TESTING
    (ns boids.test.core
    (:use [boids.core] :reload)
    (:use [clojure.test]))
    (deftest test-create-boid
    (is (= 10 (:x (create-boid 10 0 0 0 [])))
    "Create boid does not include x val"))
    (deftest test-close-boids
    (is (= 1 (count (close-boids 60 60
    #{(create-boid 80 30 10 10 [])} 100 )))
    "Close boids does not include expected"))

    View Slide

  13. SEQUENCES
    Refs
    Atomics
    Agents
    (first '(1 2 3))
    ;; 1
    (nth [1 2 3] 1)
    ;; 2
    (first {:a 1 :b 2 :c 3})
    ;; [:a 1]
    (rest #{:a :b :c})
    ;; (:c :b)
    (defn fib [a b]
    (lazy-seq (cons a (fib b (+ b a)))))
    ;; #'user/fib
    (take 5 (fib 1 1))
    ;; (1 1 2 3 5)

    View Slide

  14. INFINITE SEQUNCES
    (def users (cycle [1 2 3 4 5]))
    (defn slow-search [user]
    (Thread/sleep 1000) (println "Loop")
    (if (> (rand-int 4) 1) true false))
    (def immediate-user
    (first (filter slow-search users)))
    ;; Loops 6 times
    (time (print immediate-user))
    (2)"Elapsed time: 0.119 msecs"

    View Slide

  15. DELAYED EXECUTION
    (def lazy-user
    (take 1 (filter slow-search users)))
    ;; Immediate return
    (time (print lazy-user))
    ;; Loops 6 times
    (1) "Elapsed time: 5018.576 msecs"
    (time (print lazy-user))
    (1)"Elapsed time: 0.185 msecs"

    View Slide

  16. CONCURRENCY WITH STM
    ?
    CORE
    CORE CORE
    CORE

    View Slide

  17. CONCURRENCY WITH STM
    A 1
    A 2
    A 3
    A 4
    STATE
    IDENTITY

    View Slide

  18. Refs
    Atomics
    Agents
    (defn updateit
    [] (swap! mystate assoc :punctuation "!"))
    (def mystate
    (atom {:name "hello" :value "world"}))
    (let [foo @mystate]
    (future (updateit))
    (println foo) (println @mystate)
    (Thread/sleep 1000)
    (println foo) (println @mystate))
    {:name hello, :value world}
    {:name hello, :value world}
    {:name hello, :value world}
    {:punctuation !, :name hello, :value world}

    View Slide

  19. STM - REFS
    Refs
    Atomics
    Agents
    (def ted (ref 0)) (def bob (ref 0))
    (defn pickup [user gold]
    (dosync (commute user + gold)))
    (defn transfer [from to gold]
    (dosync
    (if (> (deref from) gold)
    (do (alter from - gold)
    (alter to + gold))
    false)))
    (pickup ted 100)
    (pickup bob 20)
    (transfer bob ted 25) ; false
    (transfer bob ted 19) ; 120 / 1

    View Slide

  20. STM - AGENTS
    (def boids (take 5
    (repeatedly
    #(agent {:x (rand-int 100)
    :y (rand-int 100)}))))
    (defn getav [dim b]
    (int (/ (reduce + (map dim b)) (count b)))
    )
    (defn behave [boid boids]
    (Thread/sleep 5000)
    {:x (getav :x boids) :y (getav :y boids)}
    )

    View Slide

  21. STM - AGENTS
    (doseq [boid boids]
    (send boid behave
    (remove #(= @boid %) (map deref boids))))
    (time (apply await boids))
    ;; "Elapsed time: 9997.488 msecs"
    (doseq [boid boids]
    (send-off boid behave
    (remove #(= @boid %) (map deref boids))))
    (time (apply await boids))
    ;; "Elapsed time: 4979.295 msecs"

    View Slide

  22. LEIN PROJECT FILE
    (defproject textapp "0.1.0-SNAPSHOT"
    :description
    "Simple text analysis rest service"
    :dependencies [
    [org.clojure/clojure "1.3.0"]
    [clojure-opennlp "0.1.9"]
    [noir "1.2.1"]]
    :main textapp.server)
    https://github.com/ianbarber/Textservice
    $ lein noir new textapp

    View Slide

  23. (defpage [:post "/verbatim"]
    {text :text :or {text ""}}
    (if (blank? text)
    (resp/json {:error "Invalid Input"})
    (resp/json
    {:tagged (tagger (tokeniser text))} )))

    View Slide

  24. CALL FROM CURL
    $ curl -X POST http://localhost:8080/
    verbatim -d "text=Hello+world+how+are
    +things+with+you?"
    {"tagged":[["Hello","UH"],["world","NN"],
    ["how","WRB"],["are","VBP"],
    ["things","NNS"],["with","IN"],
    ["you","PRP"],["?","."]]}

    View Slide

  25. (defmethod make-pos-tagger POSModel
    [model]
    (fn pos-tagger [tokens]
    (let [
    token-array (into-array tokens)
    tagger (POSTaggerME. model *beam-size*)
    tags (.tag tagger token-array)
    ]
    (with-meta (map vector tokens tags)))))

    View Slide

  26. http://clojure.org/
    WHERE TO GO NEXT?
    http://blip.tv/clojure

    View Slide

  27. ian barber - [email protected] - @ianbarber
    THANKS!

    View Slide

  28. http://flickr.com/photos/usarmyafrica/4456204113
    http://flickr.com/photos/puliarfanita/6648892997
    IMAGE CREDITS

    View Slide