Clojure Programming/Examples/Cookbook

BindingEdit

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

LoopingEdit

Loop through the items in a sequenceEdit

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 loopEdit

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

recursive loopingEdit

(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 StateEdit

How to write x = x+ 1Edit

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?

SetsEdit

How to create a setEdit

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

How to find union/intersection/difference of setsEdit

(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}

SequencesEdit

OperationsEdit

Create a list of n copies of an objectEdit

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 argumentEdit

; 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 togetherEdit

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

Infinite SequencesEdit

generate an infinite cyclic listEdit

(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 numbersEdit

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


generate an infinite repeating sequenceEdit

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

generate infinite sequence of nested function callsEdit

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)

PolymorphismEdit

Overload function based on number of arguments:

(defn argcount
   ([] 0)                                ; Zero arguments
   ([x] 1)                               ; One argument
   ([ x &  args] (inc (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"

JavaEdit

Instantiate a new Java objectEdit

(new JFrame)
 
;; or
(JFrame.)

Call a static method of a java classEdit

user=> (Math/cos 3)
-0.9899924966004454
 
user=> (. Math cos 3)
-0.9899924966004454

Call non-static method of a java objectEdit

;;method name first
(.getContentPane frame)
 
;;object first
(. frame getContentPane)

Accessing inner classesEdit

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 callsEdit

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


Simple Drawing in a windowEdit

(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 FileEdit

(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 IOEdit

Load File IO libraryEdit

(use 'clojure.contrib.duck-streams)

Read entire contents of file into stringEdit

(slurp "somefile.txt")

Write to Output FileEdit

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"

StringsEdit

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 CallsEdit

Get the current working directoryEdit

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"

ReferencesEdit

  1. range on ClojureDocs
Last modified on 18 March 2014, at 16:25