Jump to content

Clojure Programming/TJP Examples

From Wikibooks, open books for an open world
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 *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 (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)
; 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)
(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.

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