Clojure 编程/示例/食谱
外观
< Clojure 编程 | 示例
而不是像这样访问映射中的值
(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)
你可以像这样解构映射
(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)
或者更好的是,像这样
(defn list-xyz [{:keys [x, y, z]}]
(list x y z))
user=> (list-xyz {:x 1, :y 2 :z 3})
(1 2 3)
而不是像这样访问向量元素
(defn vec-norm [vec3]
(Math/sqrt (+ (* (nth vec3 0) (nth vec3 0))
(* (nth vec3 1) (nth vec3 1))
(* (nth vec3 2) (nth vec3 2)))))
你可以像这样解构向量
(defn vec-norm [[x, y, z]]
(Math/sqrt (+ (* x x) (* y y) (* z z))))
user=> (vec-norm [1, 2, 3])
3.7416573867739413
user=> (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])
user=> (dotimes [i 4] (prn i))
0
1
2
3
(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}
user=> (def x (atom 0))
#'user/x
user=> (swap! x + 1)
1
user=> (swap! x + 1)
2
user=> @x
2
或者,更惯用的方法是使用 inc
user=> (def x (atom 0))
#'user/x
user=> (swap! x inc)
1
user=> (swap! x inc)
2
user=> @x
2
最惯用的方法是不这样做。为什么要在 clojure 中做 x=x+1 呢?
(def p #{1,2,3})
(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}
user=> (repeat 10 "a")
("a" "a" "a" "a" "a" "a" "a" "a" "a" "a")
; 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)
user=> (concat [1 3] [3 4 3] [3 3])
(1 3 3 4 3 3 3)
(def x (cycle [1 2 3]))
user=> (take 12 x)
(1 2 3 1 2 3 1 2 3 1 2 3)
(def rands (repeatedly rand))
user=> (take 4 rands)
(0.39300911409554096 0.24329175257444235 0.03259576739916903 0.7459916914364135)
user=>
(def just4 (repeat 4))
user=> (take 5 just4)
(4 4 4 4 4)
无限序列 (0 1 2 3 4 5 ....) 可以使用以下方式定义:(range)从 Clojure 1.2 开始:[1]
(def integers (range))
(take 10 integers)
;; ⇒ (0 1 2 3 4 5 6 7 8 9)
或者使用以下方式: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)
根据参数数量重载函数
(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
创建根据参数数量进行分派的多分派方法
(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."
创建根据参数类进行分派的多分派方法
(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"
创建根据参数值进行分派的多分派方法
(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"
(new JFrame)
;; or
(JFrame.)
user=> (Math/cos 3)
-0.9899924966004454
user=> (. Math cos 3)
-0.9899924966004454
;;method name first
(.getContentPane frame)
;;object first
(. frame getContentPane)
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)
;; equivalent to frame.getContentPane().getSize()
(.. frame getContentPane getSize)
(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 '(cljext.swing DelegatingPanel IPainter))
导入列表中的第一项是包名,后面跟着要导入的包中所有类的名称。
注意:您必须使用包名,而不是包含类包的 jar 文件名。如果您不确定包名是什么,请从终端输入
jar tf jarfilename.jar
假设您看到类似以下内容:org/jfugue/Anticipator.class
则导入语句将是
(import '(org.jfugue Anticipator))
而不是
(import '(jarfilename Anticipator))
(use 'clojure.contrib.duck-streams)
(slurp "somefile.txt")
写入将创建一个新文件或覆盖现有文件
(spit "output.txt" "some output text")
要追加到现有文件,请使用“spit”,并将“:append”设置为 true
(spit "output.txt" "more text with spit append" :append true)
现在我们的文件应该显示
"some output textmore text with spit append"
使用str连接字符串
(str "A" "B" "C")
;; ⇒ "ABC"
并使用apply以及str作为参数连接字符串序列
(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")
使用interpose使用分隔符连接字符串序列
(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"
使用re-seq通过正则表达式在边界处拆分字符串,此处\w+表示所有字母数字字符以及“_”的 字符类
(re-seq #"\w+" "to be or not to be")
;; ⇒ ("to" "be" "or" "not" "to" "be")
反转字符串是通过以下方式完成的reverse它返回字符串中字符的序列;使用apply以及str将其再次转换为字符串
(reverse "I am cold")
;; ⇒ (\d \l \o \c \space \m \a \space \I)
(apply str (reverse "I am cold"))
;; ⇒ "dloc ma I"
以及将任何对象转换为字符串,只需将其作为参数提供给str函数
(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}"
user=> (System/getProperty "user.dir")
"/Applications/clojure"
user=> (System/setProperty "user.dir" "~/test")
"/Applications/clojure"