« Back to Index

Expanding scratch pad of Clojure code

View original Gist on GitHub

0. Clojure scratch pad.md

What we cover:

01. defining functions.clj

; defining a simple function
(defn foobar "blah" [x]
  (+ x 1))

; use the above function
; => 11
(foobar 10)

02. anonymous functions.clj

; anonymous function
; => 6
((fn [a [b c]] (+ a b c)) 1 [2 3])

03. short hand anonymous functions.clj

; short-hand anonymous function
; here is an example of a long-form anonymous function
; => {:baz 3, :foo 1}
((fn [data] (select-keys data [:foo :baz])) {:foo 1 :bar 2 :baz 3})

; here is the short-hand variation using `#()` and passing in `%` as the placeholder value
; use `%` if one arg, `%n` (e.g. `%1`, `%2` etc) when multiple args and `%&` acts like rest
(#(select-keys % [:foo :baz]) {:foo 1 :bar 2 :baz 3})

04. complex reducing.clj

; reduce two vectors into a single map
; => {:c 3, :b 2, :a 1}
(reduce
  (fn
    [m [k v]]
    (assoc m k v))
  {}
  (map vector [:a :b :c] [1 2 3]))

; break down the above reduce...

; `vector` constructs a new vector containing each argument
; => [[:a :b :c] [1 2 3]]
(vector [:a :b :c] [1 2 3])

; `map` executes the `vector` fn each loop iteration
; each loop iteration gains the first item from each vector (passed in as arguments)
; and ultimately returns a sequence constructed of vectors
; => ([:a 1] [:b 2] [:c 3])
(map vector [:a :b :c] [1 2 3])

; the result of a sequence ([:a 1] [:b 2] [:c 3]) needs to be passed without being evaluated
; so we quote the sequence (otherwise we'd need to change the sequence into an explicit vector)
; that is then passed (along with {} which acts as an accumulator)
; to an anonymous function which `reduce` then calls recursively
; {:c 3, :b 2, :a 1}
(reduce
  (fn
    [m [k v]]
    (assoc m k v))
  {}
  '([:a 1] [:b 2] [:c 3]))

; prints x and y so you can see how map passes in the first item from each vector
; note that the function doesn't return anything and so we see `nil` appear as well
; (:a 1:b 2nil :c 3nil nil)
(map (fn [x y] (pr x y)) [:a :b :c] [1 2 3])

05. alternatives to the reduce example.clj

; an alternative (expanded for easier reading) version
; where we use `do` to execute side effects
; and the function acts like it should by returning a value
; (a redundant value, but a value nonetheless)
; (:a 1:b 2"foo" :c 3"foo" "foo")
(map 
  (fn [x y] 
    (do (pr x y)) 
    "foo") 
  [:a :b :c] 
  [1 2 3])

; here is the original reduce code we had:
; (reduce (fn [m [k v]] (assoc m k v)) {} (map vector [:a :b :c] [1 2 3]))
; there are alternatives, each one becoming more focused than the other
; until we realise that Clojure has provided a function that handles exactly our use case
(apply hash-map (interleave [:a :b :c] [1 2 3]))
(into {} (map vector [:a :b :c] [1 2 3]))
(zipmap [:a :b :c] [1 2 3])

; Increment values of a map (remember we don't mutate the original data)
; {:a 2, :c 3, :b 5}
(merge-with + {:a 1, :c 3, :b 2} {:a 1 :b 3})

06. demonstrate how vectors and lists are different.clj

; vectors are added to the rear
; lists are added to the front

; vector example:
; [1 2 3 99 :bottles]
(into [1 2 3] [99 :bottles])

; list example:
; [:bottles 99 1 2 3]
; you should notice the arguments (`99` and `:bottles`) are reversed.
; this is because `99` is added to the front and then 
; `:bottles` is added to the front (pushing `99` out of first position)
(into '(1 2 3) [99 :bottles])

07. custom method that separates the specified predicate from a sequence.clj

; custom method that separates the predicate from a sequence
; a predicate is a fancy word for a function that returns a boolean (true/false) value
; e.g. from `[1 2 3 4 5]`, if the predicate is `odd?` then we'll get back `[(1 3 5) (2 4)]`
(def separate
  (fn [predicate sequence]
    [(filter predicate sequence) (remove predicate sequence)]))

; [(1 3 5) (2 4)]
(separate odd? [1 2 3 4 5])

08. destructuring with let bindings.clj

; (1 3 5)
(let [[o e] (separate odd? [1 2 3 4 5])] o)

; (2 4)
(let [[o e] (separate odd? [1 2 3 4 5])] e)

; rest using &
; x: 1 more: (2 3)
(let [[x & more] [1 2 3]]
  (println "x:" x "more:" more))

; hold the complete list using :as
; x: 1 more: (2 3) full list: [1 2 3]
(let [[x & more :as full-list] [1 2 3]]
  (println "x:" x "more:" more "full list:" full-list))

; x: 5 y: 7
(let [{the-x :x the-y :y} {:x 5 :y 7}]
  (println "x:" the-x "y:" the-y))

; The :keys directive allows you to specify keys that you would like as locals with the same name
; x: 5 y: 7
(let [{:keys [x y]} {:x 5 :y 7}]
  (println "x:" x "y:" y))

; default values
; x: 0 y: 7
(let [{:keys [x y] :or {x 0 y 0}} {:y 7}]
  (println "x:" x "y:" y))

09. utilising do to create side effects.clj

; use `do` to allow side effects...
; (1 3 5)
; (2 4)
; nil
(let [[o e] (separate odd? [1 2 3 4 5])] (do (prn o) (prn e)))

10. closures.clj

; example of closure via an anonymous function `fn [] ()`
; and use `str` for concatenation
(defn greeting
  [x]
  (fn [y] (str x y)))

(def exclaim (greeting "hello"))
(exclaim "!") ; => "hello!"

11. delays, futures, promises.clj

; the `delay` function returns an object that works much like
; an anonymous function in that the inner expression isn't evaluated until called
; the body of the `delay` object will only yield when forced using `force` or `defer/@`
(def later (fn [] (prn "a") (+ 1 1)))
(later) ; => "a" and 2 (always! it never caches the evaluation)
(def later (delay (prn "a") (+ 1 1)))
(deref later) ; => "a" and 2 on the first evaluation, but 2 for all calls after that
@later ; => interpreted as `(deref later)` also known as a 'wormhole' operator

; a `future` is a `delay` that evaluates its body in parallel
; this will evaluate all but the last expression `(+ 1 2)` in parallel
; so when testing from the REPL you'll see `#'user/x` returned as expected and
; "hi", "!", 2 will be displayed somewhere around `#'user/x` 
; (either before or after as the evaluation is happening concurrently)
(def x (future (prn "hi") (prn "!") (prn (+ 1 1)) (+ 1 2)))
@x ; => 3 (this is the last expression that was lazily evaluated and is now always returned)

; futures can cause odd side effects because of their concurrent nature
; for example if you run the following code:
(dotimes [i 5] (prn i)) ; => 0 1 2 3 4 nil (each on a separate line)
; but if you use a future then because the code executes in parallel you could see something like:
; nil02
; 4
; 1
; 
; 
; 3
(dotimes [i 5] (future (prn i)))

; notice how the return value of `nil` and the numbers `0` and `2` all executed at once
; and the line breaks were triggered in odd places.
; `agents` and `locks` apparently resolve these side effects

; delays defer evaluation, and futures parallelize them
; promises let us defer something that might not even exist yet
; we can set-up a promise and then assign something to it using `deliver`
; if we try to `deref` a promise that doesn't have any content yet then we'll wait around indefinitely!
; so make sure to `deliver` your promise before trying to deref it.
; promises also can't be changed once they've been delivered
(def box (promise))
box ; => #<core$promise$reify__6310@746f6266: :pending>
(deliver box :live-scorpions!) ; => #<core$promise$reify__6310@746f6266: :live-scorpions!>
@box ; => :live-scorpions!
(deliver box :puppy) ; => nil
@box ; => :live-scorpions!

12. atoms for thread safety.clj

; the following code first demonstrates non-thread safe code
; then we use an `atom` and its associated function `swap!` to change the value of the atom
; ultimately the code becomes thread safe
(def xs #{})
(dotimes [i 10] (future (def xs (conj xs i))))
xs ; => #{2 5 6 8 9}

; notice the set doesn't hold values zero to nine like we expect
; this is because running conj on the *current* value over multiple threads means
; we can't guarantee the value of xs (unless it's locked/synchronised/mutexed)

; here is the thread safe version
(def xs (atom #{}))
(dotimes [i 10] (future (swap! xs conj i)))
@xs ; => #{0 1 2 3 4 5 6 7 8 9}

13. macros.clj

(defmacro postfix-notation
  "I'm too indie for prefix notation"
  [expression]
  (conj (butlast expression) (last expression)))

; The expression/form (1 1 +) would normally cause an error
; But as we're calling a macro it is passed unevaluated
; => 2
(postfix-notation (1 1 +))

; We can see the evaluated result of a macro
; by using the macroexpand function along with a single quote
; to prevent evaluation (as normal functions fully evaluate their arguments)
; => ; => (+ 1 1)
(macroexpand '(postfix-notation (1 1 +)))

; Building macros is usually about constructing a list
; that when called will be evaluated
; Because of this quoting, either '(+ 1 1) or (quote (+ 1 1)), is used a lot
; This is so you can construct an unevaluated list within the macro
; See the following macro uses quotes to prevent `if` and `do` being evaluated

;; This is when's actual source
(defmacro when
  "Evaluates test. If logical true, evaluates body in an implicit do."
  {:added "1.0"}
  [test & body]
  (list 'if test (cons 'do body)))

(macroexpand '(when (the-cows-come :home)
                (call me :pappy)
                (slap me :silly)))
; =>
(if (the-cows-come :home)
  (do (call me :pappy)
      (slap me :silly)))

; Here is another macro example

(defmacro unless
  "Inverted 'if'"
  [test & branches]
  (conj (reverse branches) test 'if))

(macroexpand '(unless (done-been slapped? me)
                      (slap me :silly)
                      (say "I reckon that'll learn me")))
; =>
(if (done-been slapped? me)
  (say "I reckon that'll learn me")
  (slap me :silly))

14. macro syntax quote.clj

; Instead of having to generate lots of lists inside your macro
; all of which need to their function symbols to be quoted
; you could instead use the macro syntax quote ` and ~
; ` will return the fully qualified symbols so that the symbol includes its namespace
; so `+ will return clojure.core/+
; and `(+ 1 2) will return (clojure.core/+ 1 2)
; ~ allows you to temporarily unquote a form expression
; so `(+ 1 ~(inc 1)) returns (clojure.core/+ 1 2)

(defmacro triple [x]
  `(+ ~x ~x ~x))

; => 12
(triple 4)

; Building a list with the list function
; => (+ 1 2)
(list '+ 1 (inc 1))

; Building a list from a quoted list - super awkward
; => (+ 1 2)
(concat '(+ 1) (list (inc 1)))

; Building a list with unquoting
; => (clojure.core/+ 1 2)
`(+ 1 ~(inc 1))

15. refactoring (and unquote slicing).clj

; All of this is taken from http://www.braveclojure.com/writing-macros/

; you can define a macro that is quote complex 

(defmacro code-critic
  "phrases are courtesy Hermes Conrad from Futurama"
  [{:keys [good bad]}]
  (list 'do
        (list 'println
              "Great squid of Madrid, this is bad code:"
              (list 'quote bad))
        (list 'println
              "Sweet gorilla of Manila, this is good code:"
              (list 'quote good))))

; slight refactor with macro syntax quoting

(defmacro code-critic
  "phrases are courtesy Hermes Conrad from Futurama"
  [{:keys [good bad]}]
  ;; Notice the backtick - that's the syntax quote
  `(do (println "Great squid of Madrid, this is bad code:"
                (quote ~bad))
       (println "Sweet gorilla of Manila, this is good code:"
                (quote ~good))))

; usage
; => Cursed bacteria of Liberia, this is bad code: (1 + 1)
; => Sweet sacred boa of Western and Eastern Samoa, this is good code: (+ 1 1)
(code-critic {:good (+ 1 1) :bad (1 + 1)})

; and then refactor it so some of the complexity
; is placed inside another function
; that function is then only really useful when 
; used from inside the macro

(defn criticize-code
  [criticism code]
  `(println ~criticism (quote ~code)))

(defmacro code-critic
  [{:keys [good bad]}]
  `(do ~(criticize-code "Cursed bacteria of Liberia, this is bad code:" bad)
       ~(criticize-code "Sweet sacred boa of Western and Eastern Samoa, this is good code:" good)))

; more refactoring
(defmacro code-critic
  [{:keys [good bad]}]
  `(do ~(map #(apply criticize-code %)
             [["Great squid of Madrid, this is bad code:" bad]
              ["Sweet gorilla of Manila, this is good code:" good]])))

; uh-oh that caused an error
; use macroexpand to decipher what's happening
; for those short on time, the fix is unquote splicing ~@
; Unquote splicing is like unwrapping a seq'able data structure (examples below)

; Without unquote splicing
; => (clojure.core/+ (1 2 3))
; which would cause an error
`(+ ~(list 1 2 3))

; With unquote splicing
; => (clojure.core/+ 1 2 3)
`(+ ~@(list 1 2 3))

(defmacro code-critic
  [{:keys [good bad]}]
  `(do ~@(map #(apply criticize-code %)
              [["Sweet lion of Zion, this is bad code:" bad]
               ["Great cow of Moscow, this is good code:" good]])))
(code-critic {:good (+ 1 1) :bad (1 + 1)})

; final refactoring

(def criticisms {:good "Sweet manatee of Galilee, this is good code:"
                 :bad "Sweet giant anteater of Santa Anita, this is bad code:"})

(defn criticize-code
  [[criticism-key code]]
  `(println (~criticism-key criticisms) (quote ~code)))

(defmacro code-critic
  [code-evaluations]
  `(do ~@(map criticize-code code-evaluations)))

16. multimethod.clj

; define our multimethod `greeting` 
; and specify that :language will be the variant
(defmulti greeting :language)

; create some methods that are built from the multimethod
; the underscore in the argument list is a convention that indicates we do nothing with the argument
(defmethod greeting "English" [_] "Hi")
(defmethod greeting "French" [_] "Salut")

; test it
(greeting {:language "English"}) ; => "Hi"
(greeting {:language "French"}) ; => "Salut"

17. lazy evaluation.clj

; we'll see that the sequence is lazily evaluated
; meaning the entire range isn't created initially
; that only happens when the user requests the relevant data
(def squares
  (map 
    (fn [x] (println x) (* x x)) 
    (range 1 100)))

(first squares) ; prints 1 to 31 (as a side effect) and returns first value: 1

18. data structures.md

Lists: (1 2 3) are implemented as a Linked List and so they are more efficient for walking/iterating a long collection and adding/removing items from the beginning of the list.

Vectors: [1 2 3] have index access and are a more performant sequence collection for adding/removing items from the end of the collection. It’s best to use (peek [1 2 3]) to find the last item of the collection than (last [1 2 3]) as peek determines the best algorithm for the data structure where as last walks the collection looking for the last item.

19. channels.clj

; lein new async-test
; inside our project.clj
(defproject async-test "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [
                 [org.clojure/clojure "1.5.1"]
                 [org.clojure/core.async "0.1.303.0-886421-alpha"]])


(ns async.example
  (:require [clojure.core.async :as async :refer :all]))

; or (require '[clojure.core.async :as async :refer :all])

(def hand-off (chan)) ; create a symbol whose value is a new Channel

; (>! channel value) == put
; (<! channel) == take

(go
  (dotimes [x 10]
    (Thread/sleep 1000)
    (>! hand-off x)))

(go
  (while true
    (println (<! hand-off))))

20. refs.clj

(def bank (ref 0))
(def bank-props (ref #{"Baltic" "Park Place" "Boardwalk"}))
(def player (ref [{:money 1500
                   :props #{}}]))
@bank
;=> 0
@bank-props
;=> #{"Baltic" "Boardwalk" "Park Place"}
@player
;=> [{:money 1500, :props #{}}]
 
(defn buy-property
  [prop-name cost player-num]
  (dosync 
    (alter bank + cost)
    (alter player update-in [player-num :money] - cost)
    (alter bank-props disj prop-name)
    (alter player update-in [player-num :props] conj prop-name)))

(buy-property "Baltic" 200 0)

@bank
;=> 200
@bank-props
;=> #{"Boardwalk" "Park Place"}
@player
;=> [{:money 1300, :props #{"Baltic"}}]

21. composition.clj

(select-keys {:a 1 :b 2 :c 3} [:a :c]) ; {:c 3, :a 1}
(vals {:c 3, :a 1}) ; (3 1)

; the above can be composed manually to:
(vals (select-keys {:a 1 :b 2 :c 3} [:a :c])) ; (3 1)

; but we can use the comp function instead of that:
(def c (comp vals select-keys))
(c {:a 1 :b 2 :c 3} [:a :c]) ; (3 1)

22. partial application.clj

(defn foo [x, y, z] (prn x y z))
(foo "a" "b" "c") ; "a" "b" "c"

(def foo-a (partial foo "a"))
(foo-a "b" "c") ; "a" "b" "c"