Clojure基礎

最近看了一段clojure,下面是從書上摘下來的一下語言基礎的精華部分java

 

;函數的基本形式數組

(defn average [numbers] (/ (apply + numbers) (count numbers))) (average [60 80 100 400]) (read-string "42") (read-string "(+ 1 2)") (pr-str [1 2 3]) (read-string "[1 2 3]") "hello there" (class \c)

;;建立一份hashmap包含兩個鍵值對數據結構

(def person {:name "Sandra Cruz" :city "Protland, ME"}) (:city person) person (:user/location person) (def x 1) x


;定義變量app

(def x "hello") *ns* String Integer java.util.List java.net.Socket filter x


;quote阻止求值,'x是其簡便形式ide

(quote x) 'x


;fn是依次行定義,因此只能定義的同時使用,不能分開使用,能夠再使用def定義別名這樣就能夠屢次使用了函數

(def strange-adder (fn adder-self-reference ([x] (adder-self-reference x 1)) ([x y] (+ x y)))) (strange-adder 10) ;defn=(def (fn )) (defn adder-self-reference1 ([x] (adder-self-reference1 x 1)) ([x y] (+ x y))) (adder-self-reference1 10) (adder-self-reference1 10 50)

;可變參函數,x是一個固定參數,剩下其他的參數都被解構到rest中oop

(defn concat-rest [x & rest] (apply str (butlast rest))) (concat-rest 0 1 2 3 4)

 

;fn定義後當即須要傳入參數進行運算ui

((fn [x y] (Math/pow x y)) 2 10)


;使用#定義匿名函數spa

(#(Math/pow %1 %2) 2 10)


;匿名函數不隱含do,須要手工指定do.net

(#(do (println (str %1 \^ %2)) (Math/pow %1 %2)) 2 10)

 

;條件判斷,第一個表達式是true的話,整個if就是第二個表達式的值,不然爲第三個。任何非nil、非false的值都位true

(if (< 2 1) 2 1) (defn countdown [x] (if (zero? x) :blastoff! (do (println x) (recur (dec x))))) (countdown 0) (countdown 5)

;循環,recur可以在不消耗堆棧空間的狀況下把程序執行轉到離本地上下文最近的loop去

(loop [x 5];x=5 (if (neg? x) ;if x<0 x ;return x (recur (dec x)))) ;esle loop(x-1)


;高階函數map,將函數做用在集合上,返回一個序列

(map clojure.string/lower-case ["Java" "Imperative" "Weeping"
"Clojure" "Learning" "Peace"]) (map * [1 2 3 4] [5 6 7 8])

 

;高階函數reduce 把集合應用在一個函數而產生單個值(歸約)

(reduce max [0 -3 10 48]) (reduce + 50 [1 2 3 4]) (reduce (fn [m v] (assoc m v (* v v))) {} [1 2 3 4])

 

;偏函數,把函數的一部分參數傳給一個函數,建立一個新函數,這個函數所需參數就是剩下的那部分參數
;Clojure使用partial提供偏函數

(def only-strings (partial filter string?)) (only-strings ["a" "b" 1 2 3])

 

;使用函數組合重寫上面的函數,clojure使用comp來實現函數組合
;comp接受任意數量的函數,comp接收的參數與最後一個函數的參數個數相等,一次從最後一個函數往前調用,前一個函數的返回值是後一個函數的參數,若是不能做爲後一個函數的參數,則會報錯
;例,返回給定數字列表的全部數字總和的負數字符串形式

(defn negated-sum-str [& numbers] (str (- (apply + numbers)))) (negated-sum-str 10 12 3.4)


;函數組合的形式

(def negated-sum-str (comp str - +)) (negated-sum-str 10 12 3.4)

 

;編寫高階函數
;編寫一個高階函數。它返回某個給定數字與它的參數的和

(defn adder [n] (fn [x] (+ n x))) ((adder 5) 18)


;編寫一個高階函數,它接受一個函數做爲參數,同時返回一個函數,返回函數的做用是返回接受的函數的返回值的2倍

(defn doubler [f] (fn [& args] (* 2 (apply f args)))) ((doubler +) 1 2 3)

;能夠使用別名簡化

(def double+ (doubler +)) (double+ 1 2 3)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;日誌系統;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;定義輸入轉接 (defn print-logger [Writer];接收實現java.io.Writer接口的類實例 #(binding [*out* Writer];*out*默認綁定到標準輸出,這裏從新綁定到咱們的Writer (println %)));把要打印的消息,用println寫入到*out*(已經替換成了Writer) ;標準輸出 (def *out*-logger (print-logger *out*)) (*out*-logger "hello") ;內存buffer (def writer (java.io.StringWriter.)) (def retained-logger (print-logger writer)) (retained-logger "hello") ;打印到文件 (require 'clojure.java.io);require加載命名空間,能夠起別名(require 'clojure.java.io :as jio) (defn file-logger [file] #(with-open [f (clojure.java.io/writer file :append true)];flie以追加模式打開,並把這個writer局部命名爲f;with-open可以保證f在with-open結束的時候被關閉 ((print-logger f) %))) (def log->file (file-logger "/home//breezeli/Document/messages.log"));不指定目錄的話用light table就找不到存到哪一個目錄去了 (log->file "hello") ;記錄到多處的日誌串接,高階函數 (defn mutli-logger [& logger-fns];任意數量參數 #(doseq [f logger-fns] (f %)));dosep遍歷 (def log (mutli-logger (print-logger *out*) (file-logger "/home//breezeli/Document/messages.log"))) (log "hello again") ;每條日誌前面加時間戳 (defn timestamped-logger [logger] #(logger (format "[%1$tY-%1$tm-%1$te %1$tH:%1$tM:%1$tS] %2$s"(java.util.Date.) %))) (def log-timestamped (timestamped-logger (mutli-logger (print-logger *out*) (file-logger "/home//breezeli/Document/messages.log")))) (log-timestamped "goodbye,now")
View Code

 

;;;;;;;;;;;;;;;END;;;;;;;;;;;;;;;;;;;


;沒有反作用且調用成本很高的純函數能夠內存化加快處理速度,clojure使用memoize實現內存化

(defn prime? [n] (cond (== 1 n) false (== 2 n) true (even? n) false :else (->> (range 3 (inc (Math/sqrt n)) 2) (filter #(zero? (rem n %))) empty?)));檢測給定數字是否是素數 (time (prime? 1125899906842679)) (let [m-prime? (memoize prime?)] (time (m-prime? 1125899906842679)) (time (m-prime? 1125899906842679)))

;map、vector、set和列表是Clojure提供的基本數據解構

'(a b :name 12.5) ;;列表
['a 'b :name 12.5] ;;vector {:name "Chas" :age 31} ;;map #{1 2 3} ;;set

;Clojure中全部的數據結構都實現了Collection抽象
;Collection的提供一下核心的集合函數
;conj添加一個元素到集合,保證對於全部的集合類型,都會高效地把元素添加到列表的第一個位置,由於若是添加在最後的話須要遍歷列表,沒法保證高效
;seq獲取集合的順序視圖
;into創建在conj和seq之上
;count獲取集合的元素個數
;empty獲取一個跟所提供集合類型同樣的空集合
;=判斷兩個或多個集合是否相等
;sequence系列,一般都被叫作「seq」,除了支持Collection提供的函數外還支持
;seq返回給傳入參數的一個序列
(seq "Clojure")
;first、rest、next提供遍歷序列的方法
(first "Clojure")
(rest "Clojure")
(next "Clojure") ;若是操做的結果是空,rest始終返回一個空序列,next返回nil,這是rest和next惟一的區別
;lazy-seq建立一個內容是一個表達式結果的惰性序列

相關文章
相關標籤/搜索