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