幾分鐘內學習 Clojure

jopen 10年前發布 | 60K 次閱讀 Clojure Lisp開發

Clojure 是JVM上的一個LISP語言變種,它比Common Lisp更強調純函數式編程,但提供了一些STM工具以處理它所引入的狀態問題。

Clojure源碼托管在:github

在線練習編譯環境: himera

learnclojure.clj 示例:

; 分號作為注釋的開始

; Clojure 用一種把元素用括號括起來的像列表一樣的方式來書寫,元素之間用空格隔開 ; clojure 解釋器會把第一個元素當做是函數或者宏調用,其他的都作為參數 ; 下面這個函數用于設置當前的命名空間 (ns test)

; 更多基本的例子:

; str 函數會用它所有的參數創造一個字符串 (str "Hello" " " "World") ; => "Hello World"

; 數學運算很直觀,不過是前綴表達式 (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2

; 相等比較使用 “=”符號 (= 1 1) ; => true (= 2 1) ; => false

; 你也不必擔心邏輯運算 (not true) ; => false

; 嵌套方式正如你預料的那樣 (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2

; 類型系統 ;;;;;;;;;;;;;

; Clojure 使用java對象類型來表示 布爾值、字符串和數字 ; 使用 class函數來檢測它們. (class 1) ; 整形字面值默認是java中的Long類型 (class 1.); 浮點字面值對應著java中的Double類型 (class ""); 字符串總是用雙引號括起來,并且對應著java中的Sring類型 (class false) ;布爾值對應著java中的Boolean類型 (class nil); null值被稱為 nil(英語含義:無、零點)

; 如果你想創建一列數據字面值, 使用一個單引號 ' 來防表達式被解析執行 '(+ 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)一樣簡單, 但是我們不得不把它“引”(前面加個單引號)起來 ;這樣就能防止解釋器把它當做一個函數來解析 ;另外,(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

; 使用let 來創建臨時綁定 (let [a 1 b 2] (> a b)) ; => false

; 執行多條語句,返回最后一條語句 (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 來處理可變的類<span style="font-family:宋體;">,所有的函數始終用最初的那個對象值,最后還是返回最初的那個對象</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</pre>

來自:http://blog.csdn.net/ithomer/article/details/16807461

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!