758
技術社區[雲棲]
Clojure快餐教程(1) - 運行在JVM上的Lisp方言
Clojure快餐教程(1) - 運行在JVM上的Lisp方言
Java作為目前為止被使用最廣泛的使用虛擬機的編程語言,帶動了JVM上語言族的繁榮。
有根紅苗正的為JVM設計的動態語言Groovy,目前最主要被用於Gradle編譯環境中;也有Jython, JRuby等動態語言在JVM上的實現,也有scala這樣強大的混合語言。
在這之中,clojure是比較特殊的一種,它是Lisp語言在JVM上的一種方言。
使用clojure調用java
首先我們先看一下如何用clojure來調用java的方法。
有了這個利器之後,我們就獲得了整個java世界的類庫的強大支持。
首先我們看個例子,做個最簡單的兩個大整數的乘法。用Java寫是這樣風格的:
import java.math.BigInteger;
public class Test {
public static void test(){
BigInteger bi1 = new BigInteger("1234567890");
BigInteger bi2 = new BigInteger("9876543210");
System.out.println(bi1.multiply(bi2));
}
}
用Clojure寫起來,一開始可能會有點不適應,會是這樣的:
(ns .test2)
(import java.math.BigInteger)
(println (.multiply (new BigInteger "1234567890") (new BigInteger "9876543210")))
這裏可能會給代碼補全帶來一點困難,因為在寫.multiply
時,還不知道它是應用在哪個對象或者類上。但是Clojure就是這種風格了,函數名、運算符先行。
Clojure對於Lisp的改進
Clojure作為運行在JVM上的Lisp方言,第一個優勢就是可以無縫調用Java API。另外,針對Lisp括號多的問題,Clojure除了S表達式中常用的()
之外,增加了[]
和{}
兩種括號。
()
表示列表,[]
表示向量,{}
用於表示哈希表。
另外,#{}
用來表示集合。
user=> (class [])
clojure.lang.PersistentVector
user=> (class ())
clojure.lang.PersistentList$EmptyList
user=> (class {})
clojure.lang.PersistentArrayMap
user=> (class #{})
clojure.lang.PersistentHashSet
在Clojure中生存
查看幫助 - clojure.repl/doc
宏
doc宏用於查看常量、特殊表、函數或者宏的文檔。在以後的編程中我們會經常使用它。
例:
user=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
Prints documentation for a var or special form given its name
列表
在Lisp中,列表數據和代碼的表示形式一樣,都是S表達式。S表達式可以通俗理解為一個括號括起來的,以第一個符號進行求值的表達式。
所以,如果要避免一個列表被求值,我們有兩種辦法:
- 用list函數來生成列表
- 用quota特殊表來避免被求值
例:
user=> (list 1 2 3)
(1 2 3)
user=> (doc list)
-------------------------
clojure.core/list
([& items])
Creates a new list containing the items.
nil
user=> (quote (2 3 4))
(2 3 4)
user=> (doc quote)
-------------------------
quote
(quote form)
Special Form
Yields the unevaluated form.
Please see https://clojure.org/special_forms#quote
nil
user=> '(3 4 5)
(3 4 5)
"'"符號是quote的簡寫形式。
列表操作
lisp中最常用的car和cdr在clojure中不被支持,當然更不用想caddr之類的了。
如果要取表頭,需要使用first函數,例:
user=> (first (list 2 3 4))
2
相對地,取除了表頭之外的部分,使用rest函數,例:
user=> (rest (list 2 3 4))
(3 4)
如果取最後一個元素,可以使用last函數獲取最後一個元素,例:
user=> (last '(5 6 7))
7
一般地,我們如果想取第n個下標的元素的話,可以使用nth函數:
user=> (nth (list 8 9 10) 2)
10
雖然沒有car和cdr,但是將fist和rest連接在一起的cons函數還是有的:
user=> (cons 1 '(2 3 4))
(1 2 3 4)
向量
向量有點類似於數組,對於隨機訪問元素進行優化。clojure使用中括號來表示向量。
由於不是用的S表達式,所以也就不用quote了。
first, last, nth和rest函數對於向量仍然適用。
user=> (first [1 2 3 4])
1
user=> (nth [4 5 6 7] 3)
7
user=> (rest [3 4 5 6])
(4 5 6)
但是請注意rest返回的並不是一個向量,而且一個序列類型。
我們可以用class函數來看一下具體的類型:
user=> (class (rest '(1 2 3)))
clojure.lang.PersistentList
user=> (class (rest [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq
哈希表
用完了小括號和中括號,下麵是大括號出場的時候了。沒錯,大括號用來表示哈希表。例:
{:name "hello", :age 18}
訪問使用鍵的名字為函數名來獲取值,例:
user=> (:name {:name "Hello", :age 18})
"Hello"
集合
小中大括號都用完了腫麼辦,隻好在大括號之前加個"#"來表示。例:
user=> #{ 1 2 3}
#{1 3 2}
集合中的元素不能重複。如果要構建一個set,可以使用sorted-set函數。
user=> (sorted-set 1 2 2 3)
#{1 2 3}
變量綁定
使用def特殊表可以將值綁定到一個全局變量上。
前麵學習的數據結構,現在都可以用來綁定到變量上了。
def可以多次綁定,以最新綁定的值為準。例:
user=> (def a '(1 2 3))
#'user/a
定義函數
作為Lisp的一種方言,函數是一定在生存階段要學懂的必備技能。
我們使用fn特殊表來定義函數,如果作為函數對象,或者叫做lambda表達式,可以不定義名字。
比如,我們定義一個求平方的匿名函數:
user=> (fn [i] (* i i))
#object[user$eval17$fn__18 0x7f284218 "user$eval17$fn__18@7f284218"]
函數沒有什麼特殊的,也可以用def綁定到一個變量上,這就是我們通常定義函數的寫法:
user=> (def sqr (fn [i] (* i i)))
#'user/sqr
user=> (sqr 4)
16
我們也可以使用defn宏來定義函數:
user=> (defn sqr3 [i] (* i i i))
#'user/sqr3
user=> (sqr3 4)
64
通過defn宏,還可以為函數提供說明文檔,然後文檔就可以通過doc函數來看了。例:
user=> (defn succ "return next x" [x] (+ x 1))
#'user/succ
user=> (doc succ)
-------------------------
user/succ
([x])
return next x
nil
小結
- Clojure是一門運行在JVM上的Lisp方言。與Lisp還是有一些不同,比如使用
[]
,{}
,#{}
來表示向量、哈希表和集合。比如不支持car, cdr, setq等。 - Clojure支持通過import宏來引用java包
- Clojure通過new特殊表可以創建java對象
- clojure.core/doc函數用來查看幫助文檔
- def特殊表用於綁定變量
- fn特殊表用於定義函數,主要用於定義匿名函數
- defn宏可以定義函數的說明文檔
最後更新:2017-10-31 23:05:25
上一篇:
Sigmoid and SVM(support vertical machine)
下一篇:
阿裏雲雙11訪談之容器服務
HELLO
HDU 1166 敵兵布陣
展開關於紅警,大家在熱議 紅警2共和國(水樹奈(閆(中華人民共和國稅收征收管理法(主席令第四十九號) 2015年8月15日 - 會關於修改〈中華人民共和國文物保護法〉等十二部法律的決定》(主席令第...第八十九條 納稅人、扣繳義務人可以委托稅務代理人代為辦
Android開發11——手機橫屏和豎屏與android:configChanges
阿裏雲雙11雲產品訪談 之 互聯網中間件
Java NIO係列教程(二) Channel
GPU---並行計算利器
閃銀奇異安全負責人:互金行業安全建設的四個心得
蘋果是不是低估了三星所帶來的威脅?
QTableWidget 自定義排序