Clojure Programming/Examples/Cookbook
Binding
editHow to do structural binding or destructuring in function argument lists or let bindings.
editInstead 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
editLoop through the items in a sequence
edituser=> (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
edituser=> (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
editHow to write x = x+ 1
edituser=> (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
editHow 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
editOperations
editCreate a list of n copies of an object
edituser=> (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
edituser=> (concat [1 3] [3 4 3] [3 3])
(1 3 3 4 3 3 3)
Infinite Sequences
editgenerate 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
editThe 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
editOverload 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
editInstantiate a new Java object
edit(new JFrame)
;; or
(JFrame.)
Call a static method of a java class
edituser=> (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
editClass 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
editLoad File IO library
edit(use 'clojure.contrib.duck-streams)
Read entire contents of file into string
edit(slurp "somefile.txt")
Write to Output File
editWriting 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
editUse 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
editGet the current working directory
edituser=> (System/getProperty "user.dir")
"/Applications/clojure"
Set the current working directory (result is prior working directory)
edituser=> (System/setProperty "user.dir" "~/test")
"/Applications/clojure"