生活随笔
收集整理的這篇文章主要介紹了
几分钟内学习 Clojure
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
| Clojure是JVM上的一個LISP語言變種。它比Common Lisp更強調(diào)純函數(shù)式編程,但提供了一些STM工具以處理它所引入的狀態(tài)問題。 這個組合使并行處理更加簡單,并且通常是自動的。 (你需要Clojure 1.2或以上版本。) | Sweelia 翻譯于 2年前 1人頂 頂?翻譯的不錯哦! |
? | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | ; 分號作為注釋的開始 ; Clojure 用一種把元素用括號括起來的像列表一樣的方式來書寫,元素之間用空格隔開 ; clojure 解釋器會把第一個元素當(dāng)做是函數(shù)或者宏調(diào)用,其他的都作為參數(shù) ; 下面這個函數(shù)用于設(shè)置當(dāng)前的命名空間 (ns?test) ; 更多基本的例子: ; str 函數(shù)會用它所有的參數(shù)創(chuàng)造一個字符串 (str?"Hello" " " "World") ; =>?"Hello World" ; 數(shù)學(xué)運算很直觀,不過是前綴表達式 (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2 ;? 相等比較使用 “=”符號 (= 1 1) ; =>?true (= 2 1) ; =>?false ; 你也不必擔(dān)心邏輯運算 (not?true) ; =>?false ; 嵌套方式正如你預(yù)料的那樣 (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 ; 類型系統(tǒng) ;;;;;;;;;;;;; ; Clojure 使用java對象類型來表示 布爾值、字符串和數(shù)字 ; 使用 `class`函數(shù)來檢測它們. (class 1) ; 整形字面值默認是java中的Long類型 (class 1.); 浮點字面值對應(yīng)著java中的Double類型 (class?""); 字符串總是用雙引號括起來,并且對應(yīng)著java中的Sring類型 (class?false) ;布爾值對應(yīng)著java中的Boolean類型 (class nil); null值被稱為 nil(英語含義:無、零點) ; 如果你想創(chuàng)建一列數(shù)據(jù)字面值, 使用一個單引號 ' 來防表達式被解析執(zhí)行 '(+ 1 2) ; => (+ 1 2) ;這里沒有返回3 ; (上面表達式和(quote (+ 1 2)) 等價,不過更簡潔 ; 你可以運算一個引用列表 (eval '(+ 1 2)) ; => 3 ; 集合和序列 ;;;;;;;;;;;;;;;;;;; ; 向量和列表也是java類哦!! (class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList ;書寫一個列表形如(1 2 3)一樣簡單, 但是我們不得不把它“引”(前面加個單引號)起來 ;這樣就能防止解釋器把它當(dāng)做一個函數(shù)來解析 ;另外,(list 1 2 3) 和 '(1 2 3) 等價 ;列表和向量都是集合: (coll? '(1 2 3)) ; =>?true (coll? [1 2 3]) ; =>?true ; 只有列表是序列.(序列是有順序的) (seq? '(1 2 3)) ; =>?true (seq? [1 2 3]) ; =>?false ; 序列是列表一種邏輯上的接口,可以懶加載. ;?"懶" 意味著可以定義無窮序列,就像下面一樣: (range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (一個無窮序列) (take 4 (range)) ;? (0 1 2 3) ; 使用cons 來追加一個元素到列表或者向量的頭部 (cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3) ; 使用conj追加一個元素到列表的頭部,或者向量的尾部, (conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3) ; 使用concat來連接列表和向量 (concat [1 2] '(3 4)) ; => (1 2 3 4) ; 使用filter, map 來進行列表計算 (map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2) ; 使用reduce 來進行化繁為簡? (map/reduce 思想就來自于lisp) (reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10 ; Reduce 可以使用一個初始值 (reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1] ; 函數(shù) ;;;;;;;;;;;;;;;;;;;;; ; 使用fn來創(chuàng)建一個函數(shù)。所有的函數(shù)都有返回值,就是它的最后一個表達式 (fn []?"Hello World") ; => fn ; (你需要額外的括號去調(diào)用它) ((fn []?"Hello World")) ; =>?"Hello World" ;你可以使用def來創(chuàng)建變量 (def x 1) x ; => 1 ; 將函數(shù)賦值給一個變量 (def hello-world (fn []?"Hello World")) (hello-world) ; =>?"Hello World" ; 你可以使用defn來簡化定義過程 (defn hello-world []?"Hello World") ;[] 是函數(shù)的參數(shù)列表 (defn hello [name] ??(str?"Hello " name)) (hello?"Steve") ; =>?"Hello Steve" ; 你也可以使用下面這種簡寫方式 (def hello2?#(str "Hello " %1)) (hello2?"Fanny") ; =>?"Hello Fanny" ; 你可以創(chuàng)建擁有可變參數(shù)的函數(shù) (defn hello3 ??([]?"Hello World") ??([name] (str?"Hello " name))) (hello3?"Jake") ; =>?"Hello Jake" (hello3) ; =>?"Hello World" ; 函數(shù)允許將參數(shù)打包成列表 (有點類似python中的*) (defn count-args [& args] ??(str?"You passed " (count args)?" args: " args)) (count-args 1 2 3) ; =>?"You passed 3 args: (1 2 3)" ; 你可以將普通參數(shù)和列表參數(shù)混合使用 (defn hello-count [name & args] ??(str?"Hello " name?", you passed " (count args)?" extra args")) (hello-count?"Finn" 1 2 3) ; =>?"Hello Finn, you passed 3 extra args" ; 哈希表 ;;;;;;;;;; (class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap ; 關(guān)鍵字類似字符串,但是做了一些性能上的優(yōu)化 (class :a) ; => clojure.lang.Keyword ; Maps 的鍵可以是任意類型,但是通常推薦使用keywords (def stringmap (hash-map?"a" 1,?"b" 2,?"c" 3)) stringmap? ; => {"a" 1,?"b" 2,?"c" 3} (def keymap (hash-map :a 1 :b 2 :c 3)) keymap ; => {:a 1, :c 3, :b 2} (不保證順序) ; 順便說一下, 逗號只是為了看著更清晰,其他都和空格一樣,什么都不做. ; 從一個map中檢索一個值,可以直接把這個map當(dāng)做函數(shù)調(diào)用(這個NB) (stringmap?"a") ; => 1 (keymap :a) ; => 1 ; 關(guān)鍵字也可以當(dāng)做函數(shù)來調(diào)用,從一個map中檢索值(這個更NB) (:b keymap) ; => 2 ; stings 可沒有這個功能,所以下面會拋出異常。(這也是為什么推薦使用keywords) ;("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn ; 檢索一個不存在的值會返回nil (stringmap?"d") ; => nil ; 使用assoc 向一個map中添加新的鍵值對。 (assoc keymap :d 4) ; => {:a 1, :b 2, :c 3, :d 4} ; 請記住, clojure 類型是不可變的! keymap ; => {:a 1, :b 2, :c 3} ; 使用dissoc 來刪除key(可以刪除多個) (dissoc keymap :a :b) ; => {:c 3} ; 集合 ;;;;;; (class?#{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; =>?#{1 2 3} ; 使用con來添加新值 (conj?#{1 2 3} 4) ; => #{1 2 3 4} ; 使用disj刪除原有值 (disj?#{1 2 3} 1) ; => #{2 3} ; 直接將set當(dāng)做函數(shù)來測試是否包含某個值(NB) (#{1 2 3} 1) ; => 1? (有就返回原有的值) (#{1 2 3} 4) ; => nil (沒有就返回nil) ; clojure.sets 命名空間包含更多的函數(shù) ; 一些有用的形式 ;;;;;;;;;;;;;;;;; ; clojure中的邏輯結(jié)構(gòu)都是宏, 看起來也沒什么不同 (if false "a" "b") ; =>?"b" (if false "a") ; => nil ; 使用let 來創(chuàng)建臨時綁定 (let [a 1 b 2] ??(> a b)) ; =>?false ; 執(zhí)行多條語句,返回最后一條語句 (do ??(print?"Hello") ??"World") ; =>?"World" (prints?"Hello") ; 所有的函數(shù)都包含一個隱式的do (defn print-and-say-hello [name] ??(print?"Saying hello to " name) ??(str?"Hello " name)) (print-and-say-hello?"Jeff") ;=>?"Hello Jeff" (prints?"Saying hello to Jeff") ;?let綁定也是哦 (let [name?"Urkel"] ??(print?"Saying hello to " name) ??(str?"Hello " name)) ; =>?"Hello Urkel" (prints?"Saying hello to Urkel") ; 模塊 ;;;;;;;;;;;;;;; ; 使用“use”來獲得一個模塊中所有的函數(shù) (use 'clojure.set) ; 現(xiàn)在我們可以使用集合操作 (intersection?#{1 2 3} #{2 3 4}) ; => #{2 3}? 求交集 (difference?#{1 2 3} #{2 3 4}) ; => #{1}?? 求差集 ; 你可以只導(dǎo)入一個函數(shù)子集(例如下面只包含交集函數(shù)) (use '[clojure.set :only [intersection]]) ; 使用reqire來導(dǎo)入一個模塊 (require 'clojure.string) ; 使用/從一個模塊中調(diào)用函數(shù) (clojure.string/blank??"") ; =>?true ; 你可以在導(dǎo)入模塊的時候自定義名稱 (require '[clojure.string :as str])? (str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst." ; (#"" denotes a regular expression literal) ; 你可以使用":require" 從一個命名空間中引入模塊(use也可以,但是別這么做) ; 如果你使用:require的話,就沒必要把模塊“引”(前面加個單引號)起來了. (ns?test ??(:require ????[clojure.string :as str] ????[clojure.set :as?set])) ; Java ;;;;;;;;;;;;;;;;; ; java 擁有一個龐大的各種用途的標(biāo)準(zhǔn)庫,你一定迫不及待想學(xué)習(xí)如何在clojure中使用這些庫 ; 使用import類引入java模塊(這個還好沒變化) (import java.util.Date) ; 你也可以從一個命名空間中引入 (ns?test ??(:import java.util.Date ???????????java.util.Calendar)) ; 類名字后加個”."用來創(chuàng)建一個對象 (Date.) ; <a?date object> ; 使用. 來調(diào)用方法. 或者使用“.方法名"簡寫的方式 (. (Date.) getTime) ; <a timestamp> (.getTime (Date.)) ; 和上面一樣哦 ; 使用/ 來調(diào)用靜態(tài)方法 (System/currentTimeMillis) ; <a timestamp> (system is always present) ; 使用 doto 來處理可變的類<span style="font-family:宋體;">,所有的函數(shù)始終用最初的那個對象值,最后還是返回最初的那個對象</span> ?(import java.util.Calendar) (doto (Calendar/getInstance) ??(.set 2000 1 1 0 0 0) ??.getTime) ; => A Date.?set to 2000-01-01 00:00:00 | |
總結(jié)
以上是生活随笔為你收集整理的几分钟内学习 Clojure的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。