SlideShare a Scribd company logo
1 of 85
Download to read offline
CLOJURE BASICS
       Kyle Oba
       koba@pasdechocolat.com
       @mudphone




Tuesday, March 19, 13
Clojure 1.5 was released on March 1st, 2013.

                        Read this to see changes:
                        https://github.com/clojure/clojure/blob/master/changes.md


                        My examples use 1.4.0.




Tuesday, March 19, 13
“Startups tend to be an all or nothing
       proposition. You either get rich, or you get
       nothing. In a startup, if you bet on the
       wrong technology, your competitors will
       crush you.”
                                          Paul Graham




Tuesday, March 19, 13
“When you choose technology, you have to
       ignore what other people are doing, and
       consider only what will work the best.”


                                      Paul Graham




Tuesday, March 19, 13
“In a big company, you can do what all the
       other big companies are doing. But a
       startup can't do what all the other startups
       do. I don't think a lot of people realize this,
       even in startups.”

                                            Paul Graham




Tuesday, March 19, 13
“So if you're running a startup, you had
       better be doing something odd. If not,
       you're in trouble.”

                                         Paul Graham




Tuesday, March 19, 13
“Lisp is so great not because of some
       magic quality visible only to devotees, but
       because it is simply the most powerful
       language available. And the reason
       everyone doesn't use it is that
       programming languages are not merely
       technologies, but habits of mind as well,
       and nothing changes slower.”

                                         Paul Graham




Tuesday, March 19, 13
“I'll begin with a shockingly controversial
       statement: programming languages vary in
       power.”

                                        Paul Graham




Tuesday, March 19, 13
http://pragprog.com/book/shcloj2/programming-clojure   http://clojure.org



Tuesday, March 19, 13
Tuesday, March 19, 13
Rich Hickey is a genius.                                             And, I’m just here to piss you off.


                        Clojure Concurrency
                        http://blip.tv/clojure/clojure-concurrency-819147
                        22:00 - 23:18



                        Simple Made Easy
                        http://www.infoq.com/presentations/Simple-Made-Easy
                        15:30 - 17:15




Tuesday, March 19, 13
Why you should take a look...

                        functional langs can more easily use multiple cores


                        purely functional is awkward when dealing with state


                        Clojure has refs, agents, atoms, dynamic binding


                        dynamic typing


                        Java invocation (not functional)


                        refs (STM)


                        JVM, calling Java is idiomatic


Tuesday, March 19, 13
CLOJURE BASICS

                        Why is Clojure so cool necessary?

                        Basic Setup x2 or 3

                        Language Basics

                        Working with State (or without it)

                        Working with government forms Java

                        Macros

                        Webby Stuff

                        Testing

                        Clojure + Processing + Kinect/OpenNI



Tuesday, March 19, 13
Why is Clojure necessary?




Tuesday, March 19, 13
Multi-Core Future




Tuesday, March 19, 13
Why use the JVM?

                        The JVM is advanced technology.

                        Java libraries... lots of them.

                        Widely deployed




Tuesday, March 19, 13
Using the JVM
                                   For example: https://github.com/mmcgrana/clj-redis


                        (require '[clj-redis.client :as redis])

                        (def db (redis/init))

                        (redis/ping db)
                        => "PONG"

                        (redis/set db "foo" "BAR")
                        => "OK"

                        (redis/get db "foo")
                        => "BAR"




Tuesday, March 19, 13
JVM
                                          For example: https://github.com/mmcgrana/clj-redis

                  (ns clj-redis.client
                    (:import java.net.URI)
                    (:import (redis.clients.jedis Jedis JedisPool JedisPoolConfig JedisPubSub))
                    (:require [clojure.string :as str])
                    (:refer-clojure :exclude [get set keys type]))

                  (def ^{:private true} local-url
                    "redis://127.0.0.1:6379")

                  (defn init
                    ([] (init {}))
                    ([{:keys [url timeout test-on-borrow] :as opts}]
                       (let [uri (URI. (or url local-url))
                             tout (or timeout 2000)
                             host (.getHost uri)
                             port (if (pos? (.getPort uri)) (.getPort uri) 6379)
                             uinfo (.getUserInfo uri)
                             pass (and uinfo (last (str/split uinfo #":")))
                             config (JedisPoolConfig.)]
                         (when test-on-borrow
                           (.setTestOnBorrow config test-on-borrow))
                         (JedisPool. config host port tout pass)))
                    ([k1 v1 & {:as opts}]
                       (init (assoc opts k1 v1))))




Tuesday, March 19, 13
JVM
                                 For example: https://github.com/mmcgrana/clj-redis



                        (defn lease [^JedisPool p f]
                          (let [j (.getResource p)]
                            (try
                              (f j)
                              (finally
                                 (.returnResource p j)))))

                        (defn ping [p]
                          (lease p (fn [^Jedis j] (.ping j))))

                        (defn get [p ^String k]
                          (lease p (fn [^Jedis j] (.get j k))))

                        (defn set [p ^String k ^String v]
                          (lease p (fn [^Jedis j] (.set j k v))))




Tuesday, March 19, 13
http://www.paulgraham.com/avg.html




       Why is Clojure a secret weapon?




Tuesday, March 19, 13
Why is Clojure so cool?

                        Homoiconic


                        Modern LISP


                        Functional (but not purely functional)




Tuesday, March 19, 13
Homoiconic

                        Lisp code is just lisp data


                        Revenge of the Nerds - Paul Graham


                        Macros == black magic


                        Reprogramming the language with the language




Tuesday, March 19, 13
Modern

                        Fewer parentheses


                        Sequences


                        Reader macros for data structures


                           regex, map, set, vector, metadata


                           First-class data structures: [], {}, ‘()


                        Less Lipsy than other Lisps (ex: fns use [ ])


                        Commas are whitespace


Tuesday, March 19, 13
List Comprehension

             user> (take 40
                     (for [x (range)
                            :when (and (> (* 2 x) 99)
                                       (= 0 (mod x 3)))]
                       (* 2 x)))
             (102 108 114 120 126 132 138 144 150 156
             162 168 174 180 186 192 198 204 210 216
             222 228 234 240 246 252 258 264 270 276
             282 288 294 300 306 312 318 324 330 336)




Tuesday, March 19, 13
Functional

                        Functions are first-class


                        Data is immutable


                        Functions are NOT pure




Tuesday, March 19, 13
Why Functional?

                        Simple


                        Thread-safe


                        Parallelizable


                        Generic




Tuesday, March 19, 13
Clojure’s approach to Functional Programming

                        Not purely functional


                        Has system for working with refs, agents, atoms,
                        and dynamic binding


                        Dynamic typing


                        Java invocation is NOT functional




Tuesday, March 19, 13
“Mutable objects are the new spaghetti code.”
                                               - Rich Hickey




Tuesday, March 19, 13
Concurrency is difficult




Tuesday, March 19, 13
You can’t stop the world




                        http://clojure.org/concurrent_programming

                        http://blip.tv/clojure/clojure-concurrency-819147

                        http://www.infoq.com/presentations/Value-Values




Tuesday, March 19, 13
Concurrency is difficult

                        Persistent data structures

                        Programming with values

                        Immutable by default

                        Syntax for state:

                          Refs (STM), Agents, Atoms, Dynamic Vars

                          We’ll a bit about state later.




Tuesday, March 19, 13
Enough chit chat.




Tuesday, March 19, 13
Let’s get started

                        there are a few options


                              Emacs, Leiningen, nrepl


                              Emacs Live


                              LightTable




Tuesday, March 19, 13
Leiningen

          Clojure automation...
          https://github.com/technomancy/leiningen


          1) Download the script:

                https://raw.github.com/technomancy/leiningen/stable/bin/lein

          2) Place it on your $PATH. (I like to use ~/bin)

          3) Set it to be executable. (chmod 755 ~/bin/lein)


          Start a new project:
          $ lein new <project name>
          $ lein repl



Tuesday, March 19, 13
Emacs

          Get version >= 24.X


          Pick one (or more):


          1) http://emacsformacosx.com


          2) $ brew install emacs


          3) https://github.com/overtone/emacs-live




Tuesday, March 19, 13
Emacs                                      https://gist.github.com/mudphone/4698169
                        =   install lein 2
                        -   Do this: https://github.com/technomancy/leiningen
                        -   download lein script, it will boot strap itself
                        -   install on path, rename to lein, chmod 755
                        -   run lein --version
                            Leiningen 2.0.0 on Java 1.6.0_37 Java HotSpot(TM) 64-Bit Server VM
                         
                        =   Emacs >= 24
                        -   Download latest version: http://emacsformacosx.com, if you want the GUI version
                        -   Or, for CLI, use homebrew
                        -   Or, do both
                         
                        = Emacs Starter Kit
                        - look at my init.el
                        - install latest: https://github.com/technomancy/emacs-starter-kit
                        - install clojure-mode
                          package-install <ret> clojure-mode <ret>
                        - install nrepl
                        "   package-install <ret> nrepl <ret>
                         
                        = nrepl (already installed)
                        - docs here: https://github.com/kingtim/nrepl.el
                        - at a minimum, check out the keybindings
                         
                        = nrepl auto-complete
                        - https://github.com/purcell/ac-nrepl
                          (popup docs keybinding didn't work for me, so I'm not using it right now)
                         
                        = REFS:
                        - this isn't required reading, but it works:
                        http://www.kedrovsky.com/blog/clojure-emacs-nrepl-and-leiningen



Tuesday, March 19, 13
Emacs

                        nREPL


                            M-x nrepl-jack-in


                            C-c M-n (to switch repl to this ns)


                            C-x C-c (eval buffer in repl)


                            M-C-x (eval form under point in repl)


                            C-c C-z (switch to repl buffer)




Tuesday, March 19, 13
Clojure Basics




Tuesday, March 19, 13
Getting Started	

                        Symbols


                        Vars


                        Namespaces


                               use == require + refer


                        Help w/ doc, find-doc, source




Tuesday, March 19, 13
Forms

                        Prefix notation


                        false and nil evaluate to false


                        maps are functions of keys, and keys are functions of maps


                        defrecord




Tuesday, March 19, 13
defrecord

      user> (defrecord Person [fname lname age favorites])
      user.Person
      user> (defrecord Favorites [movie band])
      user.Favorites
      user> (def me (Person. "Kyle" "Oba" 37
                             (Favorites. "Lost in Translation" "Pantera")))
      #'user/me
      user> (:fname me)
      "Kyle"

      user> (-> me :favorites :movie)
      "Lost in Translation"

      user> (assoc me :fname "That guy")
      #user.Person{:fname "That guy", :lname "Oba", :age 37,
        :favorites #user.Favorites{:movie "Lost in Translation", :band "Pantera"}}

      user> (update-in me [:favorites :band] #(str "ZZ" % "ZZ"))
      #user.Person{:fname "Kyle", :lname "Oba", :age 37,
        :favorites #user.Favorites{:movie "Lost in Translation", :band "ZZPanteraZZ"}}




Tuesday, March 19, 13
http://clojure.org/state
       State            http://clojure.org/concurrent_programming

                        http://clojure.org/vars

                        http://clojure.org/atoms

                        http://clojure.org/agents

                        http://clojure.org/refs




Tuesday, March 19, 13
Imperative programming

                        single-threaded premise


                        world is stopped


                        requires mutexes and locks


                        difficult to get right / extremely complicated




Tuesday, March 19, 13
Identity and Value



                   identity     name   fav foods    today




                                        {cheese
                                                   March18th
                        value   Kyle     donuts
                                                     2013
                                         bacon}




Tuesday, March 19, 13
Typical OO

                        has imperative programming baked into it


                        identities are conflated with values


                        not necessarily, but usually, due to the language




Tuesday, March 19, 13
Clojure’s approach

                        separates state from identity


                        move away from state as “the content of this memory block”


                        toward “the value currently associated with this identity”


                        identity is in different states at different times


                        but, the state at a point in time never changes value




Tuesday, March 19, 13
Clojure’s approach

                        vars - root binding, refers to mutable storage location


                        vars w/ dynamic binding - per-thread binding




                        atoms


                        agents, asynchronous change via a function and values


                        refs, coordinate change with STM: software transactional memory




Tuesday, March 19, 13
Actor Model (not Clojure)

                        distributed


                        more complex


                        see Erlang




Tuesday, March 19, 13
Working with State

                        atoms


                        refs


                        dynamic binding


                               acting at a distance / aspect oriented programming


                               loss of purity


                               memoize example




Tuesday, March 19, 13
Working with State




Tuesday, March 19, 13
vars                           allow reference to mutable storage locations



                    user> (def x 1)
                    #'user/x

                    user> x
                    1

                    user> (def y 1)
                    #'user/y

                    user> (+ x y)
                    2




Tuesday, March 19, 13
dynamic binding

                    user> (def ^:dynamic x 1)
                    #'user/x

                    user> (def ^:dynamic y 1)
                    #'user/y

                    user> (+ x y)
                    2

                    user> (binding [x 2 y 3] (+ x y))
                    5

                    user> (+ x y)
                    2




Tuesday, March 19, 13
Changing State                 async   synchronous



                        coordinated               ref




                        independent   agent      atom




Tuesday, March 19, 13
atoms                          shared, synchronous, independent state



             user> (def z (atom 5))   user> (swap! z inc)
             #'user/z                 6

             user> z                  user> @z
             #<Atom@f2882ad: 5>       6

             user> @z                 user> (swap! z (constantly 10))
             5                        10

                                      user> @z
                                      10




Tuesday, March 19, 13
agents                             independent, asynchronous change



                user> (def a (agent 1))      user> (send a
                #'user/a                             #(do (Thread/sleep 5000)
                                                           (+ % 1)))
                user> a                      #<Agent@474d75ae: 2>
                #<Agent@474d75ae: 1>
                                             user> @a
                                             2

                                             user> @a
                                             3
                user> (send a inc)
                #<Agent@474d75ae: 2>

                user> a
                #<Agent@474d75ae: 2>

                user> @a
                2




Tuesday, March 19, 13
refs (transactional references)
                                       shared use of mutable storage via STM



        user> (def r (ref [1 2 3]))   (dosync (alter r #(conj % 4)))
        #'user/r                      [1 2 3 4]

        user> r                       user> @r
        #<Ref@369ca84f: [1 2 3]>      [1 2 3 4]

        user> @r
        [1 2 3]

                                      user> (dosync (alter r (partial cons 0)))
                                      (0 1 2 3 4)

                                      user> @r
                                      (0 1 2 3 4)




Tuesday, March 19, 13
Java Interop




Tuesday, March 19, 13
Working with Java

                        Calling Java


                        Java interop


                        Java collections




Tuesday, March 19, 13
Java: Examples

                        user> (System/getProperty "java.vm.version")
                        "20.14-b01-447"

                        user> (.toUpperCase "fred")
                        "FRED"

                        user> (.getName String)
                        "java.lang.String"

                        user> Math/PI
                        3.141592653589793




Tuesday, March 19, 13
Java: import and .


                   user> (import '[java.util Random])
                   java.util.Random

                   user> (def r (Random.))
                   #'user/r

                   user> (.nextInt r)
                   458809484

                   user> (.nextInt r 100)
                   42




Tuesday, March 19, 13
Java: doto




                user> (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
                #<HashMap {b=2, a=1}>




Tuesday, March 19, 13
Java: set!

                        user> (def p (java.awt.Point.))
                        #'user/p

                        user> (.x p)
                        0

                        user> (set! (. p x) 5)
                        5

                        user> p
                        #<Point java.awt.Point[x=5,y=0]>




Tuesday, March 19, 13
Macros




Tuesday, March 19, 13
What’s a Macro?

        #!/usr/bin/env ruby -w                                      $ ruby ruby_macro.rb | sh
        say_hello = "puts "hello""                                hello
                                                                    hello
        ruby_cmd = (0..9).map do |n|                                hello
          say_hello                                                 hello
        end                                                         hello
                                                                    hello
        puts "ruby -e '#{ruby_cmd.join(";")}'"                      hello
                                                                    hello
                                                                    hello
                                                                    hello




                        What if we could do this, while staying in the language?




Tuesday, March 19, 13
Ruby-like “unless” implementation as a function...

                        (defn unless [expr form]
                          (if expr nil form))

                        user> (unless (= 1 1) (println "hi"))
                        hi
                        nil




                        This won’t work, because arguments are evaluated.




Tuesday, March 19, 13
Arguments are evaluated first

                        (defn unless [expr form]
                          (println "Doing unless...")
                          (if expr nil form))

                        user> (unless (= 1 1) (println "hi"))
                        hi
                        Doing unless...
                        nil




Tuesday, March 19, 13
What we want




                        (unless expr form) -> (if expr nil form)




Tuesday, March 19, 13
What we want


                        (defmacro unless [expr form]
                          (list 'if expr nil form))

                        user> (unless true (println "yep"))
                        nil

                        user> (unless false (println "yep"))
                        yep
                        nil




Tuesday, March 19, 13
macroexpand-1

           user> (macroexpand-1 '(when-not true (println "hi")))
           (if true nil (do (println "hi")))


           user> (source when-not)
           (defmacro when-not
             "Evaluates test. If logical false, evaluates body in an implicit do."
             {:added "1.0"}
             [test & body]
               (list 'if test nil (cons 'do body)))
           nil




Tuesday, March 19, 13
WAT

                 text


                           data
              reader                 evaluation   macros
                        structures

                                      compile



                                     bytecode


Tuesday, March 19, 13
macroexpand


            user> (.. System (getProperties) (get "os.name"))
            "Mac OS X"


            user> (macroexpand-1 '(.. System (getProperties) (get "os.name")))
            (.. (. System (getProperties)) (get "os.name"))


            user> (macroexpand '(.. System (getProperties) (get "os.name")))
            (. (. System (getProperties)) (get "os.name"))




Tuesday, March 19, 13
Java Interop Bonus

         user> (source ..)
         (defmacro ..
           "form => fieldName-symbol or (instanceMethodName-symbol args*)

             Expands into a member access (.) of the first member on the first
             argument, followed by the next member on the result, etc. For
             instance:

             (.. System (getProperties) (get "os.name"))

             expands to:

             (. (. System (getProperties)) (get "os.name"))

           but is easier to write, read, and understand."
           {:added "1.0"}
           ([x form] `(. ~x ~form))
           ([x form & more] `(.. (. ~x ~form) ~@more)))
         nil




Tuesday, March 19, 13
One more macro...

          user> (source and)
          (defmacro and
            "Evaluates exprs one at a time, from left to right. If a form
            returns logical false (nil or false), and returns that value and
            doesn't evaluate any of the other expressions, otherwise it returns
            the value of the last expr. (and) returns true."
            {:added "1.0"}
            ([] true)
            ([x] x)
            ([x & next]
              `(let [and# ~x]
                 (if and# (and ~@next) and#))))
          nil




Tuesday, March 19, 13
“Webby Stuff”




Tuesday, March 19, 13
Areas of Interest:

                        ClojureScript to any old website
                        http://blip.tv/clojure/rich-hickey-unveils-clojurescript-5399498


                        ClojureScript + Three.js, to get at the WebGL bits


                        ClojureScript embedded in game systems


                        ClojureScript CLI


                        Pedestal: http://pedestal.io/documentation/hello-world-service/


                        It runs on Node.js.



Tuesday, March 19, 13
ClojureScript
        $ lein cljsbuild once
        Compiling ClojureScript.                                                 $ tree
        Compiling "resources/public/hello.js" from "src/cljs"...                 .
                                                                                 ├── README.md
        Successfully compiled "resources/public/hello.js" in 8.542318 seconds.
                                                                                 ├── doc
                                                                                 │   └── intro.md
                                                                                 ├── docroot
                                                                                 │   └── index.html
                                                                                 ├── project.clj
                                                                                 ├── resources
                                                                                 │   └── public
                                                                                 │   ├── hello.js
                                                                                 │   └── index.html
                                                                                 ├── src
                                                                                 │   ├── clj
                                                                                 │   │   └── hello_world
                                                                                 │   │   └── core.clj
                                                                                 │   └── cljs
                                                                                 │   └── hello.cljs
                                                                                 └── test
                                                                                  └── hello_world
                                                                                     └── core_test.clj

                                                                                 10 directories, 9 files


Tuesday, March 19, 13
Pedestal                            http://pedestal.io/documentation/hello-world-service/

                                                                  $ tree
                        $ lein repl                               .
                                                                  ├── README.md
                        nREPL server started on port 63132        ├── config
                        ...                                       │   └── logback.xml
                        helloworld.server=> (use 'dev)            ├── dev
                        nil                                       │   ├── dev.clj
                        helloworld.server=> (start)               │   └── user.clj
                                                                  ├── logs
                        nil
                                                                  │   └── helloworld-2013-03-18.0.log
                        helloworld.server=> (stop)
                                                                  ├── project.clj
                        nil                                       ├── src
                        helloworld.server=> Bye for now!          │   └── helloworld
                                                                  │   ├── server.clj
                                                                  │   └── service.clj
                                                                  ├── target
                                                                  │   ├── classes
                                                                  │   └── stale
                                                                  │   └── extract-native.dependencies
                                                                  └── test
                                                                    └── helloworld
                                                                      └── service_test.clj

                                                                  10 directories, 10 files

Tuesday, March 19, 13
Pedestal                      http://pedestal.io/documentation/application-introduction/
   (ns hello-world
   (:require [io.pedestal.app.protocols :as p]     (defn count-model [old-state message]
             [io.pedestal.app :as app]               (condp = (msg/type message)
             [io.pedestal.app.messages :as msg]        msg/init (:value message)
             [io.pedestal.app.render :as render]
             [domina :as dom]))
                                                       :inc (inc old-state)))

                                                   (defmulti render (fn [& args] (first args)))

                                                   (defmethod render :default [_] nil)

                                                   (defmethod render :value [_ _ old-value new-value]
                                                     (dom/destroy-children! (dom/by-id "content"))
                                                     (dom/append! (dom/by-id "content")
                                                                  (str "<h1>" new-value " Hello Worlds</h1>")))

                                                   (defn render-fn [deltas input-queue]
                                                     (doseq [d deltas] (apply render d)))

                                                   (def count-app {:models {:count {:init 0 :fn count-model}}})

                                                   (defn receive-input [input-queue]
                                                     (p/put-message input-queue {msg/topic :count msg/type :inc})
                                                     (.setTimeout js/window #(receive-input input-queue) 3000))

                                                   (defn ^:export main []
                                                     (let [app (app/build count-app)]
                                                       (render/consume-app-model app render-fn)
                                                       (receive-input (:input app))
                                                       (app/begin app)))



Tuesday, March 19, 13
Pedestal                         http://pedestal.io/documentation/application-introduction/
(ns hello-world                                      (defn count-model [old-state message]
  (:require [io.pedestal.app.protocols :as p]
            [io.pedestal.app :as app]                  (condp = (msg/type message)
            [io.pedestal.app.messages :as msg]           msg/init (:value message)
            [io.pedestal.app.render :as render]          :inc (inc old-state)))
            [io.pedestal.app.render.push :as push]
            [domina :as dom]))
                                                     (defn render-value [renderer [_ _ old-value new-value] input-queue]
                                                       (dom/destroy-children! (dom/by-id "content"))
                                                       (dom/append! (dom/by-id "content")
                                                                    (str "<h1>" new-value " Hello Worlds</h1>")))

                                                     (def count-app {:models {:count {:init 0 :fn count-model}}})

                                                     (defn receive-input [input-queue]
                                                       (p/put-message input-queue {msg/topic :count msg/type :inc})
                                                       (.setTimeout js/window #(receive-input input-queue) 3000))

                                                     (defn ^:export main []
                                                       (let [app (app/build count-app)
                                                             render-fn (push/renderer "content"
                                                                                       [[:value [:*] render-value]])]
                                                         (render/consume-app-model app render-fn)
                                                         (receive-input (:input app))
                                                         (app/begin app)))




Tuesday, March 19, 13
Testing




Tuesday, March 19, 13
Free!

       (ns oudl.core-test            user> (require '[clojure.test :as test])
         (:use clojure.test          nil
               oudl.core))
                                     user> (test/run-all-tests #"oudl.*-test")
       (deftest a-test
         (testing "FIXME, I fail."   Testing oudl.core-test
           (is (= 0 1))))
                                     FAIL in (a-test) (core_test.clj:7)
                                     FIXME, I fail.
                                     expected: (= 0 1)
                                       actual: (not (= 0 1))

                                     Ran 1 tests containing 1 assertions.
                                     1 failures, 0 errors.
                                     {:type :summary, :pass 0, :test 1, :error 0, :fail 1}




Tuesday, March 19, 13
(require ‘[clojure.test :as test])

              user> (doc test/run-all-tests)
              -------------------------
              clojure.test/run-all-tests
              ([] [re])
                Runs all tests in all namespaces; prints results.
                Optional argument is a regular expression; only namespaces with
                names matching the regular expression (with re-matches) will be
                tested.
              nil


              user> (doc test/run-tests)
              -------------------------
              clojure.test/run-tests
              ([] [& namespaces])
                Runs all tests in the given namespaces; prints results.
                Defaults to current namespace if none given. Returns a map
                summarizing test results.
              nil




Tuesday, March 19, 13
Things I Like




Tuesday, March 19, 13
Some things

                        Clojure + Processing = Quil


                        Clojure + Kinect/OpenNI = Bifocals


                        LightTable




Tuesday, March 19, 13
Tuesday, March 19, 13

More Related Content

Viewers also liked

5 Emerging Opportunities for VARs
5 Emerging Opportunities for VARs5 Emerging Opportunities for VARs
5 Emerging Opportunities for VARsthevarguy
 
ChannelCandy - Mobile Branded App for IT Channel Vendors
ChannelCandy - Mobile Branded App for IT Channel VendorsChannelCandy - Mobile Branded App for IT Channel Vendors
ChannelCandy - Mobile Branded App for IT Channel VendorsJay McBain
 
JBoss In Bossa - jBPM5 Human Interactions for System Integrators
JBoss In Bossa - jBPM5 Human Interactions for System IntegratorsJBoss In Bossa - jBPM5 Human Interactions for System Integrators
JBoss In Bossa - jBPM5 Human Interactions for System IntegratorsMauricio (Salaboy) Salatino
 
Drupal in the Enterprise: A System Integrator's Perspective
Drupal in the Enterprise: A System Integrator's PerspectiveDrupal in the Enterprise: A System Integrator's Perspective
Drupal in the Enterprise: A System Integrator's PerspectiveAcquia
 
CMB presentation for HubSpot VARs
CMB presentation for HubSpot VARsCMB presentation for HubSpot VARs
CMB presentation for HubSpot VARsbreakoutrevenue
 
iOS Prototyping with Xcode Storyboards
iOS Prototyping with Xcode StoryboardsiOS Prototyping with Xcode Storyboards
iOS Prototyping with Xcode StoryboardsKyle Oba
 

Viewers also liked (6)

5 Emerging Opportunities for VARs
5 Emerging Opportunities for VARs5 Emerging Opportunities for VARs
5 Emerging Opportunities for VARs
 
ChannelCandy - Mobile Branded App for IT Channel Vendors
ChannelCandy - Mobile Branded App for IT Channel VendorsChannelCandy - Mobile Branded App for IT Channel Vendors
ChannelCandy - Mobile Branded App for IT Channel Vendors
 
JBoss In Bossa - jBPM5 Human Interactions for System Integrators
JBoss In Bossa - jBPM5 Human Interactions for System IntegratorsJBoss In Bossa - jBPM5 Human Interactions for System Integrators
JBoss In Bossa - jBPM5 Human Interactions for System Integrators
 
Drupal in the Enterprise: A System Integrator's Perspective
Drupal in the Enterprise: A System Integrator's PerspectiveDrupal in the Enterprise: A System Integrator's Perspective
Drupal in the Enterprise: A System Integrator's Perspective
 
CMB presentation for HubSpot VARs
CMB presentation for HubSpot VARsCMB presentation for HubSpot VARs
CMB presentation for HubSpot VARs
 
iOS Prototyping with Xcode Storyboards
iOS Prototyping with Xcode StoryboardsiOS Prototyping with Xcode Storyboards
iOS Prototyping with Xcode Storyboards
 

Similar to Clojure basics

Standing on the shoulders of giants with JRuby
Standing on the shoulders of giants with JRubyStanding on the shoulders of giants with JRuby
Standing on the shoulders of giants with JRubyTheo Hultberg
 
Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013 Pablo Godel
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013Charles Nutter
 
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil BartlettDeploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlettmfrancis
 
Cook Up a Runtime with The New OSGi Resolver - Neil Bartlett
Cook Up a Runtime with The New OSGi Resolver - Neil BartlettCook Up a Runtime with The New OSGi Resolver - Neil Bartlett
Cook Up a Runtime with The New OSGi Resolver - Neil Bartlettmfrancis
 
Dynamic poly-preso
Dynamic poly-presoDynamic poly-preso
Dynamic poly-presoScott Shaw
 
Introdução Ruby On Rails
Introdução Ruby On RailsIntrodução Ruby On Rails
Introdução Ruby On RailsLukas Alexandre
 
იოსებ ძმანაშვილი Node.js
იოსებ ძმანაშვილი   Node.jsიოსებ ძმანაშვილი   Node.js
იოსებ ძმანაშვილი Node.jsunihack
 
Rust: Reach Further (from QCon Sao Paolo 2018)
Rust: Reach Further (from QCon Sao Paolo 2018)Rust: Reach Further (from QCon Sao Paolo 2018)
Rust: Reach Further (from QCon Sao Paolo 2018)nikomatsakis
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...Oursky
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...Jane Chung
 
Defensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsDefensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsRuben Tan
 
"How to use TypeORM and stay alive", Andrii Andriiko
"How to use TypeORM and stay alive", Andrii Andriiko"How to use TypeORM and stay alive", Andrii Andriiko
"How to use TypeORM and stay alive", Andrii AndriikoFwdays
 
When Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of TorqueboxWhen Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of Torqueboxrockyjaiswal
 
batou - multi(component|host|environment|.*) deployment
batou - multi(component|host|environment|.*) deploymentbatou - multi(component|host|environment|.*) deployment
batou - multi(component|host|environment|.*) deploymentChristian Theune
 
Designing for garbage collection
Designing for garbage collectionDesigning for garbage collection
Designing for garbage collectionGregg Donovan
 

Similar to Clojure basics (20)

Rails Intro & Tutorial
Rails Intro & TutorialRails Intro & Tutorial
Rails Intro & Tutorial
 
Standing on the shoulders of giants with JRuby
Standing on the shoulders of giants with JRubyStanding on the shoulders of giants with JRuby
Standing on the shoulders of giants with JRuby
 
Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013   Symfony2 and MongoDB - MidwestPHP 2013
Symfony2 and MongoDB - MidwestPHP 2013
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
 
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil BartlettDeploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
Deploying Heterogeneous Artifacts to the Cloud with OSGi - Neil Bartlett
 
Cook Up a Runtime with The New OSGi Resolver - Neil Bartlett
Cook Up a Runtime with The New OSGi Resolver - Neil BartlettCook Up a Runtime with The New OSGi Resolver - Neil Bartlett
Cook Up a Runtime with The New OSGi Resolver - Neil Bartlett
 
Dynamic poly-preso
Dynamic poly-presoDynamic poly-preso
Dynamic poly-preso
 
Java8 bench gc
Java8 bench gcJava8 bench gc
Java8 bench gc
 
Introdução Ruby On Rails
Introdução Ruby On RailsIntrodução Ruby On Rails
Introdução Ruby On Rails
 
იოსებ ძმანაშვილი Node.js
იოსებ ძმანაშვილი   Node.jsიოსებ ძმანაშვილი   Node.js
იოსებ ძმანაშვილი Node.js
 
Rejectkaigi 2010
Rejectkaigi 2010Rejectkaigi 2010
Rejectkaigi 2010
 
Rust: Reach Further (from QCon Sao Paolo 2018)
Rust: Reach Further (from QCon Sao Paolo 2018)Rust: Reach Further (from QCon Sao Paolo 2018)
Rust: Reach Further (from QCon Sao Paolo 2018)
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...
 
How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...How to write better code: in-depth best practices for writing readable, simpl...
How to write better code: in-depth best practices for writing readable, simpl...
 
Defensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.jsDefensive programming in Javascript and Node.js
Defensive programming in Javascript and Node.js
 
"How to use TypeORM and stay alive", Andrii Andriiko
"How to use TypeORM and stay alive", Andrii Andriiko"How to use TypeORM and stay alive", Andrii Andriiko
"How to use TypeORM and stay alive", Andrii Andriiko
 
When Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of TorqueboxWhen Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of Torquebox
 
batou - multi(component|host|environment|.*) deployment
batou - multi(component|host|environment|.*) deploymentbatou - multi(component|host|environment|.*) deployment
batou - multi(component|host|environment|.*) deployment
 
ADAM
ADAMADAM
ADAM
 
Designing for garbage collection
Designing for garbage collectionDesigning for garbage collection
Designing for garbage collection
 

Clojure basics

  • 1. CLOJURE BASICS Kyle Oba koba@pasdechocolat.com @mudphone Tuesday, March 19, 13
  • 2. Clojure 1.5 was released on March 1st, 2013. Read this to see changes: https://github.com/clojure/clojure/blob/master/changes.md My examples use 1.4.0. Tuesday, March 19, 13
  • 3. “Startups tend to be an all or nothing proposition. You either get rich, or you get nothing. In a startup, if you bet on the wrong technology, your competitors will crush you.” Paul Graham Tuesday, March 19, 13
  • 4. “When you choose technology, you have to ignore what other people are doing, and consider only what will work the best.” Paul Graham Tuesday, March 19, 13
  • 5. “In a big company, you can do what all the other big companies are doing. But a startup can't do what all the other startups do. I don't think a lot of people realize this, even in startups.” Paul Graham Tuesday, March 19, 13
  • 6. “So if you're running a startup, you had better be doing something odd. If not, you're in trouble.” Paul Graham Tuesday, March 19, 13
  • 7. “Lisp is so great not because of some magic quality visible only to devotees, but because it is simply the most powerful language available. And the reason everyone doesn't use it is that programming languages are not merely technologies, but habits of mind as well, and nothing changes slower.” Paul Graham Tuesday, March 19, 13
  • 8. “I'll begin with a shockingly controversial statement: programming languages vary in power.” Paul Graham Tuesday, March 19, 13
  • 9. http://pragprog.com/book/shcloj2/programming-clojure http://clojure.org Tuesday, March 19, 13
  • 11. Rich Hickey is a genius. And, I’m just here to piss you off. Clojure Concurrency http://blip.tv/clojure/clojure-concurrency-819147 22:00 - 23:18 Simple Made Easy http://www.infoq.com/presentations/Simple-Made-Easy 15:30 - 17:15 Tuesday, March 19, 13
  • 12. Why you should take a look... functional langs can more easily use multiple cores purely functional is awkward when dealing with state Clojure has refs, agents, atoms, dynamic binding dynamic typing Java invocation (not functional) refs (STM) JVM, calling Java is idiomatic Tuesday, March 19, 13
  • 13. CLOJURE BASICS Why is Clojure so cool necessary? Basic Setup x2 or 3 Language Basics Working with State (or without it) Working with government forms Java Macros Webby Stuff Testing Clojure + Processing + Kinect/OpenNI Tuesday, March 19, 13
  • 14. Why is Clojure necessary? Tuesday, March 19, 13
  • 16. Why use the JVM? The JVM is advanced technology. Java libraries... lots of them. Widely deployed Tuesday, March 19, 13
  • 17. Using the JVM For example: https://github.com/mmcgrana/clj-redis (require '[clj-redis.client :as redis]) (def db (redis/init)) (redis/ping db) => "PONG" (redis/set db "foo" "BAR") => "OK" (redis/get db "foo") => "BAR" Tuesday, March 19, 13
  • 18. JVM For example: https://github.com/mmcgrana/clj-redis (ns clj-redis.client (:import java.net.URI) (:import (redis.clients.jedis Jedis JedisPool JedisPoolConfig JedisPubSub)) (:require [clojure.string :as str]) (:refer-clojure :exclude [get set keys type])) (def ^{:private true} local-url "redis://127.0.0.1:6379") (defn init ([] (init {})) ([{:keys [url timeout test-on-borrow] :as opts}] (let [uri (URI. (or url local-url)) tout (or timeout 2000) host (.getHost uri) port (if (pos? (.getPort uri)) (.getPort uri) 6379) uinfo (.getUserInfo uri) pass (and uinfo (last (str/split uinfo #":"))) config (JedisPoolConfig.)] (when test-on-borrow (.setTestOnBorrow config test-on-borrow)) (JedisPool. config host port tout pass))) ([k1 v1 & {:as opts}] (init (assoc opts k1 v1)))) Tuesday, March 19, 13
  • 19. JVM For example: https://github.com/mmcgrana/clj-redis (defn lease [^JedisPool p f] (let [j (.getResource p)] (try (f j) (finally (.returnResource p j))))) (defn ping [p] (lease p (fn [^Jedis j] (.ping j)))) (defn get [p ^String k] (lease p (fn [^Jedis j] (.get j k)))) (defn set [p ^String k ^String v] (lease p (fn [^Jedis j] (.set j k v)))) Tuesday, March 19, 13
  • 20. http://www.paulgraham.com/avg.html Why is Clojure a secret weapon? Tuesday, March 19, 13
  • 21. Why is Clojure so cool? Homoiconic Modern LISP Functional (but not purely functional) Tuesday, March 19, 13
  • 22. Homoiconic Lisp code is just lisp data Revenge of the Nerds - Paul Graham Macros == black magic Reprogramming the language with the language Tuesday, March 19, 13
  • 23. Modern Fewer parentheses Sequences Reader macros for data structures regex, map, set, vector, metadata First-class data structures: [], {}, ‘() Less Lipsy than other Lisps (ex: fns use [ ]) Commas are whitespace Tuesday, March 19, 13
  • 24. List Comprehension user> (take 40 (for [x (range) :when (and (> (* 2 x) 99) (= 0 (mod x 3)))] (* 2 x))) (102 108 114 120 126 132 138 144 150 156 162 168 174 180 186 192 198 204 210 216 222 228 234 240 246 252 258 264 270 276 282 288 294 300 306 312 318 324 330 336) Tuesday, March 19, 13
  • 25. Functional Functions are first-class Data is immutable Functions are NOT pure Tuesday, March 19, 13
  • 26. Why Functional? Simple Thread-safe Parallelizable Generic Tuesday, March 19, 13
  • 27. Clojure’s approach to Functional Programming Not purely functional Has system for working with refs, agents, atoms, and dynamic binding Dynamic typing Java invocation is NOT functional Tuesday, March 19, 13
  • 28. “Mutable objects are the new spaghetti code.” - Rich Hickey Tuesday, March 19, 13
  • 30. You can’t stop the world http://clojure.org/concurrent_programming http://blip.tv/clojure/clojure-concurrency-819147 http://www.infoq.com/presentations/Value-Values Tuesday, March 19, 13
  • 31. Concurrency is difficult Persistent data structures Programming with values Immutable by default Syntax for state: Refs (STM), Agents, Atoms, Dynamic Vars We’ll a bit about state later. Tuesday, March 19, 13
  • 33. Let’s get started there are a few options Emacs, Leiningen, nrepl Emacs Live LightTable Tuesday, March 19, 13
  • 34. Leiningen Clojure automation... https://github.com/technomancy/leiningen 1) Download the script: https://raw.github.com/technomancy/leiningen/stable/bin/lein 2) Place it on your $PATH. (I like to use ~/bin) 3) Set it to be executable. (chmod 755 ~/bin/lein) Start a new project: $ lein new <project name> $ lein repl Tuesday, March 19, 13
  • 35. Emacs Get version >= 24.X Pick one (or more): 1) http://emacsformacosx.com 2) $ brew install emacs 3) https://github.com/overtone/emacs-live Tuesday, March 19, 13
  • 36. Emacs https://gist.github.com/mudphone/4698169 = install lein 2 - Do this: https://github.com/technomancy/leiningen - download lein script, it will boot strap itself - install on path, rename to lein, chmod 755 - run lein --version Leiningen 2.0.0 on Java 1.6.0_37 Java HotSpot(TM) 64-Bit Server VM   = Emacs >= 24 - Download latest version: http://emacsformacosx.com, if you want the GUI version - Or, for CLI, use homebrew - Or, do both   = Emacs Starter Kit - look at my init.el - install latest: https://github.com/technomancy/emacs-starter-kit - install clojure-mode package-install <ret> clojure-mode <ret> - install nrepl " package-install <ret> nrepl <ret>   = nrepl (already installed) - docs here: https://github.com/kingtim/nrepl.el - at a minimum, check out the keybindings   = nrepl auto-complete - https://github.com/purcell/ac-nrepl (popup docs keybinding didn't work for me, so I'm not using it right now)   = REFS: - this isn't required reading, but it works: http://www.kedrovsky.com/blog/clojure-emacs-nrepl-and-leiningen Tuesday, March 19, 13
  • 37. Emacs nREPL M-x nrepl-jack-in C-c M-n (to switch repl to this ns) C-x C-c (eval buffer in repl) M-C-x (eval form under point in repl) C-c C-z (switch to repl buffer) Tuesday, March 19, 13
  • 39. Getting Started Symbols Vars Namespaces use == require + refer Help w/ doc, find-doc, source Tuesday, March 19, 13
  • 40. Forms Prefix notation false and nil evaluate to false maps are functions of keys, and keys are functions of maps defrecord Tuesday, March 19, 13
  • 41. defrecord user> (defrecord Person [fname lname age favorites]) user.Person user> (defrecord Favorites [movie band]) user.Favorites user> (def me (Person. "Kyle" "Oba" 37 (Favorites. "Lost in Translation" "Pantera"))) #'user/me user> (:fname me) "Kyle" user> (-> me :favorites :movie) "Lost in Translation" user> (assoc me :fname "That guy") #user.Person{:fname "That guy", :lname "Oba", :age 37, :favorites #user.Favorites{:movie "Lost in Translation", :band "Pantera"}} user> (update-in me [:favorites :band] #(str "ZZ" % "ZZ")) #user.Person{:fname "Kyle", :lname "Oba", :age 37, :favorites #user.Favorites{:movie "Lost in Translation", :band "ZZPanteraZZ"}} Tuesday, March 19, 13
  • 42. http://clojure.org/state State http://clojure.org/concurrent_programming http://clojure.org/vars http://clojure.org/atoms http://clojure.org/agents http://clojure.org/refs Tuesday, March 19, 13
  • 43. Imperative programming single-threaded premise world is stopped requires mutexes and locks difficult to get right / extremely complicated Tuesday, March 19, 13
  • 44. Identity and Value identity name fav foods today {cheese March18th value Kyle donuts 2013 bacon} Tuesday, March 19, 13
  • 45. Typical OO has imperative programming baked into it identities are conflated with values not necessarily, but usually, due to the language Tuesday, March 19, 13
  • 46. Clojure’s approach separates state from identity move away from state as “the content of this memory block” toward “the value currently associated with this identity” identity is in different states at different times but, the state at a point in time never changes value Tuesday, March 19, 13
  • 47. Clojure’s approach vars - root binding, refers to mutable storage location vars w/ dynamic binding - per-thread binding atoms agents, asynchronous change via a function and values refs, coordinate change with STM: software transactional memory Tuesday, March 19, 13
  • 48. Actor Model (not Clojure) distributed more complex see Erlang Tuesday, March 19, 13
  • 49. Working with State atoms refs dynamic binding acting at a distance / aspect oriented programming loss of purity memoize example Tuesday, March 19, 13
  • 51. vars allow reference to mutable storage locations user> (def x 1) #'user/x user> x 1 user> (def y 1) #'user/y user> (+ x y) 2 Tuesday, March 19, 13
  • 52. dynamic binding user> (def ^:dynamic x 1) #'user/x user> (def ^:dynamic y 1) #'user/y user> (+ x y) 2 user> (binding [x 2 y 3] (+ x y)) 5 user> (+ x y) 2 Tuesday, March 19, 13
  • 53. Changing State async synchronous coordinated ref independent agent atom Tuesday, March 19, 13
  • 54. atoms shared, synchronous, independent state user> (def z (atom 5)) user> (swap! z inc) #'user/z 6 user> z user> @z #<Atom@f2882ad: 5> 6 user> @z user> (swap! z (constantly 10)) 5 10 user> @z 10 Tuesday, March 19, 13
  • 55. agents independent, asynchronous change user> (def a (agent 1)) user> (send a #'user/a #(do (Thread/sleep 5000) (+ % 1))) user> a #<Agent@474d75ae: 2> #<Agent@474d75ae: 1> user> @a 2 user> @a 3 user> (send a inc) #<Agent@474d75ae: 2> user> a #<Agent@474d75ae: 2> user> @a 2 Tuesday, March 19, 13
  • 56. refs (transactional references) shared use of mutable storage via STM user> (def r (ref [1 2 3])) (dosync (alter r #(conj % 4))) #'user/r [1 2 3 4] user> r user> @r #<Ref@369ca84f: [1 2 3]> [1 2 3 4] user> @r [1 2 3] user> (dosync (alter r (partial cons 0))) (0 1 2 3 4) user> @r (0 1 2 3 4) Tuesday, March 19, 13
  • 58. Working with Java Calling Java Java interop Java collections Tuesday, March 19, 13
  • 59. Java: Examples user> (System/getProperty "java.vm.version") "20.14-b01-447" user> (.toUpperCase "fred") "FRED" user> (.getName String) "java.lang.String" user> Math/PI 3.141592653589793 Tuesday, March 19, 13
  • 60. Java: import and . user> (import '[java.util Random]) java.util.Random user> (def r (Random.)) #'user/r user> (.nextInt r) 458809484 user> (.nextInt r 100) 42 Tuesday, March 19, 13
  • 61. Java: doto user> (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2)) #<HashMap {b=2, a=1}> Tuesday, March 19, 13
  • 62. Java: set! user> (def p (java.awt.Point.)) #'user/p user> (.x p) 0 user> (set! (. p x) 5) 5 user> p #<Point java.awt.Point[x=5,y=0]> Tuesday, March 19, 13
  • 64. What’s a Macro? #!/usr/bin/env ruby -w $ ruby ruby_macro.rb | sh say_hello = "puts "hello"" hello hello ruby_cmd = (0..9).map do |n| hello say_hello hello end hello hello puts "ruby -e '#{ruby_cmd.join(";")}'" hello hello hello hello What if we could do this, while staying in the language? Tuesday, March 19, 13
  • 65. Ruby-like “unless” implementation as a function... (defn unless [expr form] (if expr nil form)) user> (unless (= 1 1) (println "hi")) hi nil This won’t work, because arguments are evaluated. Tuesday, March 19, 13
  • 66. Arguments are evaluated first (defn unless [expr form] (println "Doing unless...") (if expr nil form)) user> (unless (= 1 1) (println "hi")) hi Doing unless... nil Tuesday, March 19, 13
  • 67. What we want (unless expr form) -> (if expr nil form) Tuesday, March 19, 13
  • 68. What we want (defmacro unless [expr form] (list 'if expr nil form)) user> (unless true (println "yep")) nil user> (unless false (println "yep")) yep nil Tuesday, March 19, 13
  • 69. macroexpand-1 user> (macroexpand-1 '(when-not true (println "hi"))) (if true nil (do (println "hi"))) user> (source when-not) (defmacro when-not "Evaluates test. If logical false, evaluates body in an implicit do." {:added "1.0"} [test & body] (list 'if test nil (cons 'do body))) nil Tuesday, March 19, 13
  • 70. WAT text data reader evaluation macros structures compile bytecode Tuesday, March 19, 13
  • 71. macroexpand user> (.. System (getProperties) (get "os.name")) "Mac OS X" user> (macroexpand-1 '(.. System (getProperties) (get "os.name"))) (.. (. System (getProperties)) (get "os.name")) user> (macroexpand '(.. System (getProperties) (get "os.name"))) (. (. System (getProperties)) (get "os.name")) Tuesday, March 19, 13
  • 72. Java Interop Bonus user> (source ..) (defmacro .. "form => fieldName-symbol or (instanceMethodName-symbol args*) Expands into a member access (.) of the first member on the first argument, followed by the next member on the result, etc. For instance: (.. System (getProperties) (get "os.name")) expands to: (. (. System (getProperties)) (get "os.name")) but is easier to write, read, and understand." {:added "1.0"} ([x form] `(. ~x ~form)) ([x form & more] `(.. (. ~x ~form) ~@more))) nil Tuesday, March 19, 13
  • 73. One more macro... user> (source and) (defmacro and "Evaluates exprs one at a time, from left to right. If a form returns logical false (nil or false), and returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expr. (and) returns true." {:added "1.0"} ([] true) ([x] x) ([x & next] `(let [and# ~x] (if and# (and ~@next) and#)))) nil Tuesday, March 19, 13
  • 75. Areas of Interest: ClojureScript to any old website http://blip.tv/clojure/rich-hickey-unveils-clojurescript-5399498 ClojureScript + Three.js, to get at the WebGL bits ClojureScript embedded in game systems ClojureScript CLI Pedestal: http://pedestal.io/documentation/hello-world-service/ It runs on Node.js. Tuesday, March 19, 13
  • 76. ClojureScript $ lein cljsbuild once Compiling ClojureScript. $ tree Compiling "resources/public/hello.js" from "src/cljs"... . ├── README.md Successfully compiled "resources/public/hello.js" in 8.542318 seconds. ├── doc │   └── intro.md ├── docroot │   └── index.html ├── project.clj ├── resources │   └── public │   ├── hello.js │   └── index.html ├── src │   ├── clj │   │   └── hello_world │   │   └── core.clj │   └── cljs │   └── hello.cljs └── test └── hello_world └── core_test.clj 10 directories, 9 files Tuesday, March 19, 13
  • 77. Pedestal http://pedestal.io/documentation/hello-world-service/ $ tree $ lein repl . ├── README.md nREPL server started on port 63132 ├── config ... │   └── logback.xml helloworld.server=> (use 'dev) ├── dev nil │   ├── dev.clj helloworld.server=> (start) │   └── user.clj ├── logs nil │   └── helloworld-2013-03-18.0.log helloworld.server=> (stop) ├── project.clj nil ├── src helloworld.server=> Bye for now! │   └── helloworld │   ├── server.clj │   └── service.clj ├── target │   ├── classes │   └── stale │   └── extract-native.dependencies └── test └── helloworld └── service_test.clj 10 directories, 10 files Tuesday, March 19, 13
  • 78. Pedestal http://pedestal.io/documentation/application-introduction/ (ns hello-world (:require [io.pedestal.app.protocols :as p] (defn count-model [old-state message] [io.pedestal.app :as app] (condp = (msg/type message) [io.pedestal.app.messages :as msg] msg/init (:value message) [io.pedestal.app.render :as render] [domina :as dom])) :inc (inc old-state))) (defmulti render (fn [& args] (first args))) (defmethod render :default [_] nil) (defmethod render :value [_ _ old-value new-value] (dom/destroy-children! (dom/by-id "content")) (dom/append! (dom/by-id "content") (str "<h1>" new-value " Hello Worlds</h1>"))) (defn render-fn [deltas input-queue] (doseq [d deltas] (apply render d))) (def count-app {:models {:count {:init 0 :fn count-model}}}) (defn receive-input [input-queue] (p/put-message input-queue {msg/topic :count msg/type :inc}) (.setTimeout js/window #(receive-input input-queue) 3000)) (defn ^:export main [] (let [app (app/build count-app)] (render/consume-app-model app render-fn) (receive-input (:input app)) (app/begin app))) Tuesday, March 19, 13
  • 79. Pedestal http://pedestal.io/documentation/application-introduction/ (ns hello-world (defn count-model [old-state message] (:require [io.pedestal.app.protocols :as p] [io.pedestal.app :as app] (condp = (msg/type message) [io.pedestal.app.messages :as msg] msg/init (:value message) [io.pedestal.app.render :as render] :inc (inc old-state))) [io.pedestal.app.render.push :as push] [domina :as dom])) (defn render-value [renderer [_ _ old-value new-value] input-queue] (dom/destroy-children! (dom/by-id "content")) (dom/append! (dom/by-id "content") (str "<h1>" new-value " Hello Worlds</h1>"))) (def count-app {:models {:count {:init 0 :fn count-model}}}) (defn receive-input [input-queue] (p/put-message input-queue {msg/topic :count msg/type :inc}) (.setTimeout js/window #(receive-input input-queue) 3000)) (defn ^:export main [] (let [app (app/build count-app) render-fn (push/renderer "content" [[:value [:*] render-value]])] (render/consume-app-model app render-fn) (receive-input (:input app)) (app/begin app))) Tuesday, March 19, 13
  • 81. Free! (ns oudl.core-test user> (require '[clojure.test :as test]) (:use clojure.test nil oudl.core)) user> (test/run-all-tests #"oudl.*-test") (deftest a-test (testing "FIXME, I fail." Testing oudl.core-test (is (= 0 1)))) FAIL in (a-test) (core_test.clj:7) FIXME, I fail. expected: (= 0 1) actual: (not (= 0 1)) Ran 1 tests containing 1 assertions. 1 failures, 0 errors. {:type :summary, :pass 0, :test 1, :error 0, :fail 1} Tuesday, March 19, 13
  • 82. (require ‘[clojure.test :as test]) user> (doc test/run-all-tests) ------------------------- clojure.test/run-all-tests ([] [re]) Runs all tests in all namespaces; prints results. Optional argument is a regular expression; only namespaces with names matching the regular expression (with re-matches) will be tested. nil user> (doc test/run-tests) ------------------------- clojure.test/run-tests ([] [& namespaces]) Runs all tests in the given namespaces; prints results. Defaults to current namespace if none given. Returns a map summarizing test results. nil Tuesday, March 19, 13
  • 83. Things I Like Tuesday, March 19, 13
  • 84. Some things Clojure + Processing = Quil Clojure + Kinect/OpenNI = Bifocals LightTable Tuesday, March 19, 13