Clojure 编程/TJP 示例
外观
user=> (-> "hello" .toUpperCase (.replace "H" "J"))
"JELLO"
然而 -> 在所有内容上都能起作用
user=> (-> true (if inc dec) (map [1 2 3]))
(2 3 4)
或者扩展
(map (if true inc dec) [1 2 3])
所以也可以在 -> 中使用宏和普通函数,即非方法。
(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 [*test-out* System/out] (run-tests))
user=> (butlast "hello")
(\h \e \l \l)
(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 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}
注意:doto 在修改后返回对象,这非常方便。在上面的例子中,不需要变量绑定来访问结果对象。
(.addChild *scene-graph*
(doto (KeyNavigatorBehavior.
(-> *universe* .getViewingPlatform .getViewPlatformTransform))
(setSchedulingBounds (BoundingSphere. (Point3d.) 10000.0))))
在这里您可以看到使用 doto 比使用 let 创建临时绑定的替代方法更具可读性。
(defn factorial [n]
(apply * (range 2 (inc n))))
user=> (apply str (interpose " " (reverse (.split "I am cold" " "))))
"cold am I"
user=> (into-array (map double-array [[1.0] [2.0]]))
#<double[][] [[D@1fa1bb6>
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))))
(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")
使用 fn,或者更好的是,有一个自定义语法来创建匿名函数
(map #(println "hi" %) ["mum" "dad" "sister"])
主体中的参数由参数文字的存在决定,参数文字采用 %、%n 或 %& 的形式。% 是 %1 的同义词,%n 指定第 n 个参数(从 1 开始),%& 指定剩余参数。
user=> (map + [1 2 3 4] [1 2 3 4])
(2 4 6 8)
(map (memfn charAt i) ["fred" "ethel" "lucy"] [1 2 3])
-> (\r \h \y)
(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))
参见 loop
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
user=> (rem 5 2)
1
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 {"ll" ""} "hello world")
(require '[clojure.zip :as zip])
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
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]]