Clojure Programming/TJP Examples
Appearance
->
[edit | edit source]user=> (-> "hello" .toUpperCase (.replace "H" "J"))
"JELLO"
However -> works on everything
user=> (-> true (if inc dec) (map [1 2 3]))
(2 3 4)
or expanded
(map (if true inc dec) [1 2 3])
So one can also use macros and normal functions in ->, i.e. non-methods.
accessor
[edit | edit source](def unit-test-name (accessor unit-test :name))
user=> (def e-str (struct employee "John" 123))
#'user/e-str
user=> e-str
{"name" "John", "id" 123}
user=> ("name" e-str) ; FAIL: string not an accessor
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn
at user.eval__2537.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:3847)
at clojure.lang.Repl.main(Repl.java:75)
user=> (def e-name (accessor employee "name")) ; bind accessor to e-name
#'user/e-name
user=> (e-name e-str) ; use accessor
"John"
binding
[edit | edit source](binding [*test-out* System/out] (run-tests))
butlast
[edit | edit source]user=> (butlast "hello")
(\h \e \l \l)
concat
[edit | edit source](defn poly-expand
poly-expand [points]
(loop [aa (first points) remaining (rest points) built (empty points)]
(if (empty? remaining)
(concat built [aa (first points)])
(recur (first remaining) (rest remaining)
(concat built [aa (first remaining)])))))
(poly-expand '[a b c d])
-> [a b b c c d d a]
def
[edit | edit source](def *a* 10)
defmulti
[edit | edit source]defmethod
[edit | edit source](defmulti fib int)
(defmethod fib 0 [_] 1)
(defmethod fib 1 [_] 1)
(defmethod fib :default [n] (+ (fib (- n 2)) (fib (- n 1))))
user=> (map fib (range 10))
(1 1 2 3 5 8 13 21 34 55)
doto
[edit | edit source](doto (new java.util.HashMap) (put "a" 1) (put "b" 2))
-> {a=1, b=2}
NB: doto returns the object after modification, which is very convenient. Consider in the above example no variable binding is required to access the resultant object.
(.addChild *scene-graph*
(doto (KeyNavigatorBehavior.
(-> *universe* .getViewingPlatform .getViewPlatformTransform))
(setSchedulingBounds (BoundingSphere. (Point3d.) 10000.0))))
Here you can see it is much more readable using doto than the alternative which would be to create a temporary binding with let.
interpose
[edit | edit source]apply
[edit | edit source](defn factorial [n]
(apply * (range 2 (inc n))))
reverse
[edit | edit source]user=> (apply str (interpose " " (reverse (.split "I am cold" " "))))
"cold am I"
into-array
[edit | edit source]double-array
[edit | edit source]user=> (into-array (map double-array [[1.0] [2.0]]))
#<double[][] [[D@1fa1bb6>
filter
[edit | edit source]user=> (filter identity [1 2 nil false 4])
(1 2 4)
loop
[edit | edit source]; compute the factorial of 5, establishes two 'variables' cnt and acc
; cnt is decremented every call until it reaches 0
; acc stores the result of multiplying each value cnt took
(loop [cnt 5 acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt))))
lazy-cons
[edit | edit source](defn fib-seq []
((fn rfib [a b]
(lazy-cons a (rfib b (+ a b))))
0 1))
user> (take 20 (fib-seq))
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
fn
[edit | edit source](map (fn [a] (str "hi " a)) ["mum" "dad" "sister"])
; => ("hi mum" "hi dad" "hi sister")
"lambda"
[edit | edit source]Use fn, or even better there is a custom syntax to create an anonymous function:
(map #(println "hi" %) ["mum" "dad" "sister"])
Arguments in the body are determined by the presence of argument literals taking the form %, %n or %&. % is a synonym for %1, %n designates the nth arg (1-based), and %& designates a rest arg.
map
[edit | edit source]user=> (map + [1 2 3 4] [1 2 3 4])
(2 4 6 8)
memfn
[edit | edit source](map (memfn charAt i) ["fred" "ethel" "lucy"] [1 2 3])
-> (\r \h \y)
proxy
[edit | edit source](defn rev-vector-seq
[v]
(when (< 0 (count v))
(proxy [clojure.lang.ISeq] []
(seq [] this)
(first [] (peek v))
(rest [] (rev-vector-seq (pop v))))))
(doto (javax.swing.JFrame.)
(addKeyListener (proxy [java.awt.event.KeyListener] []
(keyPressed [e] (println (.getKeyChar e) " key pressed"))
(keyReleased [e] (println (.getKeyChar e) " key released"))
(keyTyped [e] (println (.getKeyChar e) " key typed"))))
(setVisible true))
recur
[edit | edit source]See loop
ref
[edit | edit source]ref-set
[edit | edit source]user=> (def foo (ref 0))
#'user/foo
user=> foo
#<Ref clojure.lang.Ref@7c2479a4>
user=> @foo
0
user=> (ref-set foo 1)
java.lang.IllegalStateException: No transaction running (NO_SOURCE_FILE:0)
user=> (dosync (ref-set foo 1))
1
user=> @foo
1
"remainder" "%" "mod"
[edit | edit source]rem
[edit | edit source]user=> (rem 5 2)
1
remove
[edit | edit source]The opposite of filter
(remove nil? [1 2 nil 3 false 4 5])
-> (1 2 3 false 4 5)
(remove #{2 4} [1 2 nil 3 false 4 5])
-> (1 nil 3 false 5)
replace
[edit | edit source](replace {"ll" ""} "hello world")
require
[edit | edit source](require '[clojure.zip :as zip])
assoc
[edit | edit source]defstruct
[edit | edit source]struct
[edit | edit source]struct-map
[edit | edit source]user=> (defstruct employee :name :id)
#'user/employee
user=> (struct employee "Mr. X" 10)
{:name "Mr. X", :id 10}
user=> (struct-map employee :id 20 :name "Mr. Y")
{:name "Mr. Y", :id 20}
user=> (def a (struct-map employee :id 20 :name "Mr. Y"))
#'user/a
user=> (def b (struct employee "Mr. X" 10))
#'user/b
user=> (:name a) ; observe that :name is an accessor
"Mr. Y"
user=> (:id b) ; same with :id
10
user=> (b :id)
10
user=> (b :name)
"Mr. X"
user=> (assoc a :name "New Name")
{:name "New Name", :id 20}
user=> a ; note that 'a' is immutable and did not change
{:name "Mr. Y", :id 20}
user=> (def a1 (assoc a :name "Another New Name")) ; bind to a1
#'user/a1
user=> a1
{:name "Another New Name", :id 20}
test
[edit | edit source]user=> (defn
#^{:test (fn []
(assert (= 4 (myadd 2 2))))}
myadd [a b]
(+ a b))
#'user/myadd
user=> (test #'myadd)
:ok
zippers
[edit | edit source]user=> (-> (zip/vector-zip [[1 2] 3 [[4 5] 7 8]])
zip/down
zip/right
zip/right
zip/down
zip/down
zip/right
(zip/edit inc)
zip/root)
[[1 2] 3 [[4 6] 7 8]]