Clojure Programming/Examples/Cookbook

Binding edit

How to do structural binding or destructuring in function argument lists or let bindings. edit

Instead of accessing values in a map like this:

(defn list-xyz [xyz-map]
  (list (:x xyz-map) (:y xyz-map) (:z xyz-map)))

user=> (list-xyz {:x 1, :y 2 :z 3})
(1 2 3)

You can destructure the map like this:

(defn list-xyz [{x :x, y :y, z :z}]
  (list x y z))

user=> (list-xyz {:x 1, :y 2, :z 3})
(1 2 3)

or better yet, like this:

(defn list-xyz [{:keys [x, y, z]}]
  (list x y z))

user=> (list-xyz {:x 1, :y 2 :z 3})
(1 2 3)

Instead of accessing vector elements like this:

(defn vec-norm [vec3]
  (Math/sqrt (+ (* (nth vec3 0) (nth vec3 0))
		(* (nth vec3 1) (nth vec3 1))
		(* (nth vec3 2) (nth vec3 2)))))

you can destructure the vector like this:

(defn vec-norm [[x, y, z]]
  (Math/sqrt (+ (* x x) (* y y) (* z z))))

user=> (vec-norm [1, 2, 3])
3.7416573867739413

Looping edit

Loop through the items in a sequence edit

user=> (doseq [ item '((1 2) [3 4] "D")] (prn item))
(1 2)
[3 4]
"D"
nil

user=> (doseq [item {:a 1 :b 2}] (prn item))
[:b 2]
[:a 1]

user=> (for [item {:a 1 :b 2}] item)
([:a 1] [:b 2])

for loop edit

user=> (dotimes [i 4] (prn i))
0
1
2
3

recursive looping edit

(defn my-zipmap [keys vals]
  (loop [my-map {}
         my-keys keys
         my-vals vals]
    (if (and (seq my-keys) (seq my-vals))
      (recur (assoc my-map (first my-keys) (first my-vals))
             (rest my-keys)
             (rest my-vals))
      my-map)))

(println (my-zipmap [:a :b :c] [1 2 3]))

{:c 3, :b 2, :a 1}

Modifying State edit

How to write x = x+ 1 edit

user=> (def x (atom 0))
#'user/x
user=> (swap! x + 1)
1
user=> (swap! x + 1)
2
user=> @x
2

Or, a more idiomatic way would be to use inc:

user=> (def x (atom 0))
#'user/x
user=> (swap! x inc)
1
user=> (swap! x inc)
2
user=> @x
2

The most idiomatic way is not do this at all. Why would you want to do x=x+1 in clojure?

Sets edit

How to create a set edit

(def p #{1,2,3})

How to find union/intersection/difference of sets edit

(def a #{1,2,3,4})
(def b #{2,3,5})

user=> (clojure.set/union a b)
#{1 2 3 4 5}

user=> (clojure.set/intersection a b)
#{2 3}

user=> (clojure.set/difference a b)
#{1 4}

Sequences edit

Operations edit

Create a list of n copies of an object edit

user=> (repeat 10 "a")
("a" "a" "a" "a" "a" "a" "a" "a" "a" "a")

Create a list of n calls to a function of no argument edit

; repeatedly generates an infinite sequence of calls to a function that takes no arguments
; No calls are made until the result is needed! (do not try to evaluate this list directly, it is infinite, 
; and will run forever)
user=> (def random-ints (repeatedly #(rand-int 100)))

; use take to take the integers:
user=> (take 10 random-ints)
(66 8 31 90 78 18 28 8 94 3)

;NOTE: seqs are cached, so taking new random ints will always return the same result.
;This also means that if you take many ints from a global seq (def'd one) ALL the integers will
;stay in memory until the name is redefined to something else!

user=> (take 15 random-ints) ; first 10 are the same, 5 new ints generated
(66 8 31 90 78 18 28 8 94 3 84 29 71 85 41)

; to avoid a global list, you can do this:
(defn make-calls [n func]
  (take n (repeatedly func)))

; no fear of keeping huge lists in memory this time (unless you hold onto them, of course)
user=> (make-calls 5 #(rand-int 100))
(60 75 89 62 36)

; upon next call, the result will be different:
user=> (make-calls 5 #(rand-int 100))
(94 95 88 11 93)

append or concatenate two more sequences together edit

user=> (concat [1 3] [3 4 3] [3 3])
(1 3 3 4 3 3 3)

Infinite Sequences edit

generate an infinite cyclic list edit

(def x (cycle [1 2 3]))

user=> (take 12 x)
(1 2 3 1 2 3 1 2 3 1 2 3)

generate an infinite sequence of random numbers edit

(def rands (repeatedly rand))

user=> (take 4 rands)
(0.39300911409554096 0.24329175257444235 0.03259576739916903 0.7459916914364135)
user=>

generate an infinite repeating sequence edit

(def just4 (repeat 4))

user=> (take 5 just4)
(4 4 4 4 4)

generate infinite sequence of nested function calls edit

The infinite sequence (0 1 2 3 4 5 ....) can be defined using (range) since clojure 1.2:[1]

 (def integers (range))
 (take 10 integers)
 ;; ⇒ (0 1 2 3 4 5 6 7 8 9)

or alternatively using iterate:

 ;; Generates (x (inc  x) (inc (inc  x)) ...)
 (def integers (iterate inc 0))
 (take 4 integers)
 ;; ⇒ (0 1 2 3)
 (def newton (iterate (fn[x] (/ (+ x (/ 2.0 x)) 2)) 2))
 (take 5 newton)
 ;; ⇒ (2 1.5 1.4166666666666665 1.4142156862745097 1.4142135623746899)

Polymorphism edit

Overload function based on number of arguments:

(defn argcount
   ([] 0)                                ; Zero arguments
   ([x] 1)                               ; One argument
   ([x &  args] (+ 1 (count args))))    ; List of arguments

(argcount)
;; ⇒ 0
(argcount "dog")
;; ⇒ 1
(argcount "cat" 1 3 4)
;; ⇒ 4

Create multi-method which dispatches on the number of its arguments:

(defmulti g (fn[& arglist] (count arglist)))
(defmethod g 0 [& arglist] "No arguments.")
(defmethod g 1 [& arglist] "One argument.")
(defmethod g 2 [& arglist]  "Two arguments.")
(defmethod g :default [& arglist] "More than two arguments.")

(g)                    ; ⇒ "No arguments."
(g 1)                  ; ⇒ "One argument."
(g 2)                  ; ⇒ "One argument."
(g 3 4)                ; ⇒ "Two arguments."
(g "cart" 1 [2 3 ])    ; ⇒ "More than two arguments."

Create a multi-method which dispatches on the class of its arguments:

(comment Define f to be a multi-method function and dispatch using class of argument)
(defmulti f class)

(comment Use this definition for f if the class of the argument x is a long)
(defmethod f Long [x] "Argument is a long")

(comment Use this definition for f if the class of the argument x is a double)
(defmethod f Double [x] "Argument is a double")

(comment Use this definition for f for all other argument types )
(defmethod f :default [x] "Argument is not a number")

(f 3)               ; ⇒ "Argument is a long"
(f 3.4)             ; ⇒ "Argument is a double"
(f "string")        ; ⇒ "Argument is not a number"
(comment Define g to be a multi-method function which dispatches on the class of its arguments)
(defmulti g (fn[x,y] [(class x) (class y )]))

(comment Use this definition for g if class of first argument is a long and class of second argument is a long)
(defmethod g [Long,Long]  [x,y] "Both arguments are longs")

(comment Use this definition for g if class of first argument is long and class of second argument is double)
(defmethod g [Long,Double] [x,y] "First argument is a long and second argument is a double")

(comment Use this definition for g as the default )
(defmethod g :default [x,y] "All other cases")

(g 3 2)         ; ⇒ "Both arguments are longs"
(g 3 4.3)       ; ⇒ "First argument is a long and second argument is a double"
(g 4.3 4.3)     ; ⇒ "All other cases"

Create a multi-method that dispatches on the value of its argument:

(comment Create multi method h that dispatches on the value of the argument)
(defmulti h (fn[x] x))

(comment Use this definition for h if argument is 4)
(defmethod h 4 [x] "argument is 4")

(comment Use this definition for other values of h)
(defmethod h :default [x] "argument is not 4")

(h 4)          ; ⇒ "argument is 4"
(h 3)          ; ⇒ "argument is not 4"
(h [3 34])     ; ⇒ "argument is not 4"

(comment Create multi method h that dispatches on the value of the argument being in an interval)
(defmulti h (fn [x] (<= 4 x 10)))

(comment Use this definition for h if argument is between 4 and 10 )
(defmethod h true [x] "argument is between 4 and 10")
    
(comment Use this definition for other values of h)
(defmethod h :default [x] "argument is not between 4 and 10")

(h 1)        ; ⇒ "argument is not between 4 and 10"
(h 4)        ; ⇒ "argument is between 4 and 10"
(h 10)       ; ⇒ "argument is between 4 and 10"
(h 11)       ; ⇒ "argument is not between 4 and 10"

Java edit

Instantiate a new Java object edit

(new JFrame)

;; or
(JFrame.)

Call a static method of a java class edit

user=> (Math/cos 3)
-0.9899924966004454

user=> (. Math cos 3)
-0.9899924966004454

Call non-static method of a java object edit

;;method name first
(.getContentPane frame)

;;object first
(. frame getContentPane)

Accessing inner classes edit

Class definition in Java.

public class OkCancelDialog {
  //Inner class
  public static enum State {
    OK, CANCEL;
  };
}
;;accessing the inner class and its static fields
(println OkCancelDialog$State/OK)
(println OkCancelDialog$State/CANCEL)

Nested series of method calls edit

;; equivalent to frame.getContentPane().getSize()
(.. frame getContentPane getSize)

Simple Drawing in a window edit

(ns drawing-demo
  (:import [javax.swing JPanel JFrame]
           [java.awt Dimension]))

(defn make-panel []
  (let [panel (proxy [JPanel] []
                (paintComponent [g]
                  (.drawLine g 0 0 100 100)))]
    (doto panel
      (.setPreferredSize (Dimension. 400 400)))))

(defn make-frame [panel]
  (doto (new JFrame)
    (.add panel)
    .pack
    .show))

(make-frame (make-panel))

Import Java Classes from Jar File edit

(import '(cljext.swing DelegatingPanel IPainter))

The first item in the import list is the package name followed by the names of all the classes in the package to import.

Note: you must use the package name and not the name of the jar file which contains the package of classes. If you're not sure what the package name is, from a terminal type:

jar tf jarfilename.jar

Let's say you see something like: org/jfugue/Anticipator.class

Then the import statement would be:

(import '(org.jfugue Anticipator))

Not:

(import '(jarfilename Anticipator))

File IO edit

Load File IO library edit

(use 'clojure.contrib.duck-streams)

Read entire contents of file into string edit

(slurp "somefile.txt")

Write to Output File edit

Writing creates a new file or will overwrite existing file

(spit "output.txt" "some output text")

To append to existing file use "spit" with ":append" set to true

(spit "output.txt" "more text with spit append" :append true)

Now our file should say:

"some output textmore text with spit append"

Strings edit

Use str to concatenate strings:

(str "A" "B" "C")
;; ⇒ "ABC"

and use apply with str as an argument to concatenate a sequence of strings:

(apply str ["A" "B" "C"])
;; ⇒ "ABC"
(apply str ["/usr/include" \/ "stdio.h"])
;; ⇒ "/usr/include/stdio.h"

(map 
 (fn [file] (str "/usr/include/" file ".h"))
 ["stdio" "gmp" "signal"])
;; ⇒ ("/usr/include/stdio.h" "/usr/include/gmp.h" "/usr/include/signal.h")

Use interpose to join a sequence of strings with a separator:

(apply str (interpose \: ["A" "B" "C"]))
;; ⇒ "A:B:C"

(apply str 
  (interpose \:
    ["/usr/local/sbin" "/usr/local/bin" "/usr/sbin" "/usr/bin" "/sbin" "/bin"]))
;; ⇒ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Use re-seq to split a string at boundaries by a regular expression, here \w+ denotes a character class of all alphanumeric characters plus "_":

(re-seq #"\w+" "to be or not to be")
;; ⇒ ("to" "be" "or" "not" "to" "be")

Reversing a string is done via reverse which returns a sequence of the characters in the string; use apply with str to turn it into a string again:

(reverse "I am cold")
;; ⇒ (\d \l \o \c \space \m \a \space \I)

(apply str (reverse "I am cold"))
;; ⇒ "dloc ma I"

and to convert any object into a string simply supply it as an argument to the str function:

(str 3)             ; ⇒ "3"
(str 3.0)           ; ⇒ "3.0"
(str 'a)            ; ⇒ "a"
(str '(1 2))        ; ⇒ "(1 2)"
(str {:a 1 :b 2})   ; ⇒ "{:a 1, :b 2}"

Operating System Calls edit

Get the current working directory edit

user=> (System/getProperty "user.dir") 
"/Applications/clojure"

Set the current working directory (result is prior working directory) edit

user=> (System/setProperty "user.dir" "~/test") 
"/Applications/clojure"

References edit

  1. range on ClojureDocs