Clojure 是一種運行在 Java 平臺上的 LISP 方言,LISP 是一種以表達性和功能強大著稱的編程語言。java
; 分號做爲註釋的開始
; clojure 用括號把元素括起來,元素之間用空格隔開。clojure 解釋器把第一個元素當作是函數或者宏調用,其餘的元素都做爲參數
; 下面這個函數用於設置當前的命名空間
(ns myclojure)
; 一些簡單的例子: (str "Hello" " " "World") ; => "Hello World" (+ 2 1) ; => 3 (- 2 1) ; => 1 (* 2 2) ; => 4 (/ 2 1) ; => 2
; 比較使用 "=" (= 1 1) ; => true (= 2 1) ; => false
; 邏輯運算 (not true) ; => false
; 嵌套預算 (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2
; defn 定義一個函數
; doseq 相似 for 循環
(defn Example [] (doseq [n [0 1 2]] (println n))) (Example)
; 使用let 來建立臨時綁定 (let [a 1 b 2] (> a b)) ; => false
; clojure 把布爾值、字符串、數字、向量、列表轉化爲 java 對象 (class 1) ; 整形字面值默認是 java 中的 Long 類型 (class 1.); 浮點字面值對應着 java 中的 Double 類型 (class ""); 字符串老是用雙引號括起來,而且對應着 java 中的 Sring 類型 (class false) ;布爾值對應着 java 中的 Boolean 類型 (class nil); null值被稱爲 nil (class [1 2 3]) ; => clojure.lang.PersistentVector (class '(1 2 3)) ; => clojure.lang.PersistentList
; 若是想建立一列數據字面值, 使用一個單引號 ' 來防表達式被解析執行 '(+ 1 2) ; => (+ 1 2) ;這裏沒有返回3 ; (上面表達式和(quote (+ 1 2)) 等價,不過更簡潔 ; 能夠運算一個引用列表 (eval '(+ 1 2)) ; => 3 ;書寫一個列表如(1 2 3)同樣簡單, 可是咱們不得不把它「引」(前面加個單引號)起來 ;這樣就能防止解釋器把它當作一個函數來解析 ;另外,(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] ; 使用 fn 來建立一個函數。全部的函數都有返回值,就是它的最後一個表達式 (fn [] "Hello World") ; => fn ; (你須要額外的括號去調用它) ((fn [] "Hello World")) ; => "Hello World" ;你可使用def來建立變量 (def x 1) x ; => 1 ; 將函數賦值給一個變量 (def hello-world (fn [] "Hello World")) (hello-world) ; => "Hello World" ; 你可使用defn來簡化定義過程 (defn hello-world [] "Hello World") ;[] 是函數的參數列表 (defn hello [name] (str "Hello " name)) (hello "Steve") ; => "Hello Steve" ; 你也可使用下面這種簡寫方式 (def hello2 #(str "Hello " %1)) (hello2 "Fanny") ; => "Hello Fanny" ; 你能夠建立擁有可變參數的函數 (defn hello3 ([] "Hello World") ([name] (str "Hello " name))) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World" ; 函數容許將參數打包成列表 (有點相似python中的*) (defn count-args [& args] (str "You passed " (count args) " args: " args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" ; 你能夠將普通參數和列表參數混合使用 (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 ; 關鍵字相似字符串,可是作了一些性能上的優化 (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當作函數調用(這個NB) (stringmap "a") ; => 1 (keymap :a) ; => 1 ; 關鍵字也能夠當作函數來調用,從一個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當作函數來測試是否包含某個值(NB) (#{1 2 3} 1) ; => 1 (有就返回原有的值) (#{1 2 3} 4) ; => nil (沒有就返回nil) ; clojure.sets 命名空間包含更多的函數 ; clojure中的邏輯結構都是宏, 看起來也沒什麼不一樣 (if false "a" "b") ; => "b" (if false "a") ; => nil ; 執行多條語句,返回最後一條語句 (do (print "Hello") "World") ; => "World" (prints "Hello") ; 全部的函數都包含一個隱式的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」來得到一個模塊中全部的函數 (use 'clojure.set) ; 如今咱們可使用集合操做 (intersection #{1 2 3} #{2 3 4}) ; => #{2 3} 求交集 (difference #{1 2 3} #{2 3 4}) ; => #{1} 求差集 ; 你能夠只導入一個函數子集(例以下面只包含交集函數) (use '[clojure.set :only [intersection]]) ; 使用reqire來導入一個模塊 (require 'clojure.string) ; 使用/從一個模塊中調用函數 (clojure.string/blank? "") ; => true ; 你能夠在導入模塊的時候自定義名稱 (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 擁有一個龐大的各類用途的標準庫,你必定火燒眉毛想學習如何在clojure中使用這些庫 ; 使用import類引入java模塊(這個還好沒變化) (import java.util.Date) ; 你也能夠從一個命名空間中引入 (ns test (:import java.util.Date java.util.Calendar)) ; 類名字後加個」."用來建立一個對象 (Date.) ; <a date object> ; 使用. 來調用方法. 或者使用「.方法名"簡寫的方式 (. (Date.) getTime) ; <a timestamp> (.getTime (Date.)) ; 和上面同樣哦 ; 使用/ 來調用靜態方法 (System/currentTimeMillis) ; <a timestamp> (system is always present) ; 使用 doto 來處理可變的類,全部的函數始終用最初的那個對象值,最後仍是返回最初的那個對象 (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