幾分鐘內(nèi)學(xué)習(xí)Clojure
作者:佚名
Clojure是JVM上的一個LISP語言變種。它比Common Lisp更強調(diào)純函數(shù)式編程,但提供了一些STM工具以處理它所引入的狀態(tài)問題。
此處獲取源碼: test.clj
Clojure是JVM上的一個LISP語言變種。它比Common Lisp更強調(diào)純函數(shù)式編程,但提供了一些STM工具以處理它所引入的狀態(tài)問題。
這個組合使并行處理更加簡單,并且通常是自動的。
(你需要Clojure 1.2或以上版本。)
- ; 分號作為注釋的開始
- ; 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
譯文鏈接:http://www.oschina.net/translate/learn-clojure-in-minutes
責(zé)任編輯:林師授
來源:
OSCHINA編譯