Clojure Programming/TJP Examples

From Wikibooks, open books for an open world
Jump to: navigation, search

->[edit]

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]

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

(binding [*test-out* System/out] (run-tests))

butlast[edit]

user=> (butlast "hello")
(\h \e \l \l)

concat[edit]

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

(def *a* 10)

defmulti[edit]

defmethod[edit]

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

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

apply[edit]

(defn factorial [n] 
  (apply * (range 2 (inc n)))) 

reverse[edit]

user=> (apply str (interpose " " (reverse (.split "I am cold" " "))))
"cold am I"

into-array[edit]

double-array[edit]

user=> (into-array (map double-array [[1.0] [2.0]])) 
#<double[][] [[D@1fa1bb6> 

filter[edit]

user=> (filter identity [1 2 nil false 4]) 
(1 2 4)

loop[edit]

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

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

(map (fn [a] (str "hi " a)) ["mum" "dad" "sister"])
; => ("hi mum" "hi dad" "hi sister")

"lambda"[edit]

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]

user=> (map + [1 2 3 4] [1 2 3 4])
(2 4 6 8)

memfn[edit]

(map (memfn charAt i) ["fred" "ethel" "lucy"] [1 2 3])
-> (\r \h \y)

proxy[edit]

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

See loop

ref[edit]

ref-set[edit]

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]

rem[edit]

user=> (rem 5 2) 
1 

remove[edit]

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]

(replace {"ll" ""} "hello world") 

require[edit]

(require '[clojure.zip :as zip]) 

assoc[edit]

defstruct[edit]

struct[edit]

struct-map[edit]

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]

user=> (defn
  #^{:test (fn []
    (assert (= 4 (myadd 2 2))))}
  myadd [a b]
  (+ a b))
#'user/myadd
user=> (test #'myadd)
:ok

zippers[edit]

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]]