Clojure API 文档

_images/clojure-icon.gif

这是 Clojure 官方 API 文档 clojure.github.com/clojure 的中文翻译版本。

翻译工作目前正在进行中,欢迎加入: github.com/huangz1990/clojure_api_cn

目录:

clojure.core

->

(-> x)
(-> x form)
(-> x form & more)

将多个形式串连成一个表达式。

如果只有一个参数 x 和一个形式 form ,那么将 x 作为第二个项(item),插入到 form 当中,如果 form 不是一个列表,那么将 form 包裹到一个列表里面。[译注:举个例子, (-> a-map :key) 会展开成 (:key a-map) ,而不是 :key a-map 。]

如果有多于一个形式,那么将第一个形式作为第二个项插入到第二个形式中,以此类推。

查看源码

; 应用多个函数

user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)
"X"

user=> (use '[clojure.walk :only [macroexpand-all]])
nil

user=> (macroexpand-all '(-> "a b c d"
                             .toUpperCase
                             (.replace "A" "X")
                             (.split " ")
                             first))
(first (. (. (. "a b c d" toUpperCase) replace "A" "X") split " "))

; 从深层嵌套的 map 中取出值

user=> (def language {:clojure {:author {:first-name "Rich" :last-name "Hickey"}}})
#'user/language

user=> (:first-name (:author (:clojure language)))
"Rich"

user=> (-> language :clojure :author :first-name)
"Rich"

->>

(->> x form)
(->> x form & more)

将多个形式串连成一个表达式。

如果只有一个参数 x 和一个形式 form ,那么将 x 作为最后一项(item),插入到 form 当中,如果 form 不是一个列表,那么将 form 包裹到一个列表里面。[译注:举个例子, (->> a-map :key) 会展开成 (:key a-map) ,而不是 :key a-map 。]

如果有多于一个形式,那么将第一个形式作为最后一项插入到第二个形式中,以此类推。

查看源码

; 计算小于 10 的整数的平方之和

user=> (->> (range)
            (map #(* % %))
            (filter even?)
            (take 10)
            (reduce +))
1140

user=> (use '[clojure.walk :only [macroexpand-all]])
nil

user=> (macroexpand-all '(->> (range)
                              (map #(* % %))
                              (filter even?)
                              (take 10)
                              (reduce +)))
(reduce + (take 10 (filter even? (map (fn* [p1__3#] (* p1__3# p1__3#)) (range)))))

->

(-> x)
(-> x form)
(-> x form & more)

将多个形式串连成一个表达式。

如果只有一个参数 x 和一个形式 form ,那么将 x 作为第二个项(item),插入到 form 当中,如果 form 不是一个列表,那么将 form 包裹到一个列表里面。[译注:举个例子, (-> a-map :key) 会展开成 (:key a-map) ,而不是 :key a-map 。]

如果有多于一个形式,那么将第一个形式作为第二个项插入到第二个形式中,以此类推。

查看源码

; 应用多个函数

user=> (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)
"X"

user=> (use '[clojure.walk :only [macroexpand-all]])
nil

user=> (macroexpand-all '(-> "a b c d"
                             .toUpperCase
                             (.replace "A" "X")
                             (.split " ")
                             first))
(first (. (. (. "a b c d" toUpperCase) replace "A" "X") split " "))

; 从深层嵌套的 map 中取出值

user=> (def language {:clojure {:author {:first-name "Rich" :last-name "Hickey"}}})
#'user/language

user=> (:first-name (:author (:clojure language)))
"Rich"

user=> (-> language :clojure :author :first-name)
"Rich"

->>

(->> x form)
(->> x form & more)

将多个形式串连成一个表达式。

如果只有一个参数 x 和一个形式 form ,那么将 x 作为最后一项(item),插入到 form 当中,如果 form 不是一个列表,那么将 form 包裹到一个列表里面。[译注:举个例子, (->> a-map :key) 会展开成 (:key a-map) ,而不是 :key a-map 。]

如果有多于一个形式,那么将第一个形式作为最后一项插入到第二个形式中,以此类推。

查看源码

; 计算小于 10 的整数的平方之和

user=> (->> (range)
            (map #(* % %))
            (filter even?)
            (take 10)
            (reduce +))
1140

user=> (use '[clojure.walk :only [macroexpand-all]])
nil

user=> (macroexpand-all '(->> (range)
                              (map #(* % %))
                              (filter even?)
                              (take 10)
                              (reduce +)))
(reduce + (take 10 (filter even? (map (fn* [p1__3#] (* p1__3# p1__3#)) (range)))))

aclone

(aclone array)

返回Java数组的克隆,作用于已知类型的数组

user=> (def a (int-array [1 2 3 4]))
#'user/a

user=> (def b (aclone a))
#'user/b

user=> (aset b 0 23)
23

user=> (vec b)
[23 2 3 4]

user=> (vec a)
[1 2 3 4]

alength

(alength array)

返回Java数组长度,作用于所有类型

(def array (into-array Integer/TYPE [1 2 3 4 5]))
#'user/array

(alength array)
5

alter-var-root

(alter-var-root v f & args)

原子性地修改 var v 的值,新值由 v 的旧值和给定的 args 应用到函数 f 得出。

查看源码

user=> (def v 10)
#'user/v

user=> (alter-var-root (var v) + 1)     ; (var v) 等同于 #'v
11

user=> v
11

assoc

(assoc map key val)
(assoc map key val & kvs)

assoc 表示 associate 的意思。

assoc 接受一个 Map ,还有一个或多个 key-val 对, 返回一个和传入 Map 类型相同的新 Map , 除了原来传入 Map 已有的数据外, 新 Map 还包含传给 assoc 的那些 key-val 对。

当一个向量被应用到 assoc 函数时, 返回一个新向量, 新向量的索引下标(index) key 的值就是 val

注意索引下标必须 <= (count vector)

user=> (assoc {} :Clojure "Rich")
{:Clojure "Rich"}

user=> (assoc {:Clojure "Rich"} :Clojure "Rich Hickey")     ; 如果有同名 key ,那么那么覆盖它
{:Clojure "Rich Hickey"}

user=> (assoc [1 2 3] 0 10086)
[10086 2 3]

user=> (assoc [1 2 3] 3 10086)          ; key 最大可以等于 (count vector)
[1 2 3 10086]

user=> (assoc [1 2 3] 10086 10086)      ; key 不能大于 (count vector)
IndexOutOfBoundsException   clojure.lang.PersistentVector.assocN
(PersistentVector.java:136)

bigdec

(bigdec x)

x 强制转换为 BigDecimal

查看源码

user=> (bigdec 3.0)
3.0M

user=> (bigdec 5)
5M

user=> (bigdec -1)
-1M

user=> (bigdec -1.0)
-1.0M

bigint

(bigint x)

x 强制转换为 BigInt

查看源码

user=> (def x (biginteger 19931029))
#'user/x

user=> (class x)
java.math.BigInteger

biginteger

(biginteger x)

x 强制转换为 BigInteger

查看源码

user=> (def x (biginteger 19931029))
#'user/x

user=> (class x)
java.math.BigInteger

comment

(comment & body)

忽略 body ,返回 nil

查看源码

user=> (comment hello-clojure)
nil

user=> (comment "clojure!")
nil

user=> (defn msg []
         (comment "nothing but a greeting message here")
         (println "hello"))
#'user/msg

user=> (msg)
hello
nil

comp

(comp)
(comp f)
(comp f g)
(comp f g h)
(comp f g h & other-functions)

comp 接受一系列函数作为输入, 返回一个匿名函数。

这个匿名函数接受可变数量的参数(variable number of args), 并按从右到左的顺序, 将传入的函数应用到参数中。

user=> ((comp str double +) 3 3 3)  ; 以下两个表达等价
"9.0"

user=> (str (double (+ 3 3 3)))
"9.0"

compile

(compile lib)

编译符号(symbol) lib 定义的命名空间到一系列的class文件。 lib 的源文件必须在正确的类关联(classpath-relative)的目录下,输出的文class文件将会在 *compile-path* 定义的目录里,这个目录也必须在类路径(classpath)里面。

查看源码

complement

(complement f)

接受一个函数 f ,返回一个匿名函数。

这个匿名函数接受的参数、产生的作用都和 f 一样, 但它返回的真值和 f 相反。

user=> (defn f []
           (println "hello")
           false)
#'user/f

user=> (f)
hello
false

user=> ((complement f))
hello
true

concat

(concat)
(concat x)
(concat x y)
(concat x y & zs)

返回一个惰性序列,序列里包含所有传入 collection 的全部元素。

; 另个、一个或多个 collection 组合

user=> (concat)
()

user=> (concat [1])
(1)

user=> (concat [1] [2])
(1 2)

user=> (concat [1] [2] [3])
(1 2 3)

user=> (concat [1] [2] [3] [4 5 6])
(1 2 3 4 5 6)


; 传入 concat 的参数必须都是 collection
; 组合元素和 collection 是 cons 和 conj 的任务

; user=> (concat 1 [2 3])
; IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:487)

cond

(cond & clauses)

接受一系列 test/expression 对, 它每次对一个 test 进行求值, 如果某个 test 返回 true , 那么 cond 求值并返回与这个 test 相对应的 expression , 并且不再对其他 test 进行求值。

(cond) 返回 nil

user=> (defn type-of-number [n]
           (cond (> n 0) "positive number"
                 (< n 0) "negative number"
                 :else "zero"))
#'user/type-of-number

user=> (type-of-number 10)
"positive number"

user=> (type-of-number -5)
"negative number"

user=> (type-of-number 0)
"zero"

conj

(conj coll x)
(conj coll x & xs)

conj 的完整词义是 conjoin , 表示『相连接』的意思, 它用于将元素和 collection 拼接起来。

需要注意的是, 根据 coll 的类型, 组合会发生在 coll 的不同地方, 也即是, 元素 x 可能会被加入到 coll 的最左边,也可能会被加入到最右边。

coll 等于 nil , 也即是,执行 (conj nil item) 时, 结果为 (item)

; coll 为 nil

user=> (conj nil 1)
(1)


; 向量的组合在尾部进行

user=> (conj [0 1 2] 3)
[0 1 2 3]


; 列表的组合在头部进行

user=> (conj (list 0 1 2) 3)
(3 0 1 2)


; 处理多个元素的 conj
; 注意向量和列表的结果之间的不同

user=> (conj [0 1 2] 3 4 5)
[0 1 2 3 4 5]

user=> (conj (list 0 1 2) 3 4 5)
(5 4 3 0 1 2)

cons

(cons x seq)

返回一个新的序列, 序列的第一个元素是 x , 而 seq 则是序列的其余部分。

; cons 起数字 1 和空列表

user=> (cons 1 '())
(1)


; cons 起数字 1 和列表 (2 3)

user=> (cons 1 (list 2 3))
(1 2 3)

constantly

(constantly x)

返回一个匿名函数, 接受任何数量的参数, 但总是返回 x

user=> (def ten (constantly 10))
#'user/ten

user=> (ten)
10

user=> (ten 1)
10

user=> (ten 1 2)
10

user=> (ten 1 2 3)
10

contains?

(contains? coll key)

如果 key 存在于给定 coll 中, 那么返回 true ,否则返回 false

对于那些使用数值索引(index)的 collection 、比如向量和 Java 数组来说, contains? 用于测试给定的数值 key 是否在索引的范围(range)之内。

contains? 不是线性复杂度的操作, 它可以在常数或对数复杂度内完成。

如果要检查一个 coll 是否符合某个条件,可以使用 some 函数。

user=> (contains? {:clojure "Rich"} :python)        ; 测试 Map
false

user=> (contains? {:clojure "Rich"} :clojure)
true

user=> (contains? [1 3 5 7 9] 3)                    ; 测试向量
true

user=> (contains? [1 3 5 7 9] 10086)
false

count

(count coll)

返回 coll 中元素的数量。

(count nil) 返回 0

coll 也可以是字符串、数组、Java Collection 和 Map 。

user=> (count nil)
0

user=> (count [1 2 3 4])
4

user=> (count (list 1 2 3 4))
4

user=> (count "string")
6

user=> (count {:clojure "Rich" :python "Guido" :ruby :Matz})
3

counted?

(counted? coll)

如果 coll 实现了常数复杂度的 count 操作,那么返回 true

; 向量、列表、Map 和集合的 count 操作都是常数复杂度的
; 但字符串不是

user=> (counted? [1 2 3])
true

user=> (counted? '(1 2 3))
true

user=> (counted? {:clojure "Rich"})
true

user=> (counted? #{:a :b :c})
true

user=> (counted? "string")
false

declare

(declare & names)

定义一些无绑定的 var 名字,用于提前声明(forward declarations)。

user=> (defn f []
           (g))
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: g in this context, compiling:(NO_SOURCE_PATH:2)

user=> (declare g)
#'user/g

user=> (defn f []
            (g))
#'user/f

defn-

(defn- name & decls)

作用和 defn 类似,唯一的不同是创建的函数是私有的。

user=> (defn- msg [] "hello moto")
#'user/msg

user=> (msg)
"hello moto"

user=> (meta #'msg)
{:arglists ([]), :ns #<Namespace user>, :name msg, :private true, :line 1, :file "NO_SOURCE_PATH"}

defonce

(defonce name expr)

name 的 root value 设置为 expr 的值,当且仅当 name 还没有设置 root value 。

如果 name 已经有 root value ,那么 expr 不会被求值。

user=> number                       ; 没有 root value
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: number in this context, compiling:(NO_SOURCE_PATH:0)

user=> (defonce number 10086)       ; 设置 root value
#'user/number

user=> number
10086

user=> (defonce number 123123)      ; 已有 root value ,设置失败
nil

user=> number
10086

defprotocol

(defprotocol name & opts+sigs)

协议是一组命名方法和签名

(defprotocol IOFactory
  (make-reader [this] "Create a Buffered Reader")
  (make-writer [this] "Create a Buffered Writer")
)

delay

(delay & body)

参数 body 接受一系列表达式,并返回一个 Delay 对象。

这个 Delay 对象只有在第一次被 force 函数、 deref 函数或者 @ 宏强迫求值时,才会对 body 进行求值。

body 的求值结果会被缓存,之后对这个 Delay 对象的所有强迫求值,都返回这个缓存结果。

查看源码

user=> (def d (delay (println "force delay object")
                     (+ 1 1)))
#'user/d

user=> d
#<Delay@15c5bba: :pending>

user=> @d
force delay object      ; 第一次强迫求值
2                       ; 这个值会被缓存

user=> @d
2                       ; 不再求值 body ,只返回缓存值

user=> d
#<Delay@15c5bba: 2>     ; 打印值现在带有 body 的值

delay?

(delay? x)

如果 x 是用 delay 创建的一个 Delay 对象,那么返回 true

查看源码

user=> (delay? 2)
false

user=> (delay? (delay))
true

deref

(deref ref)
(deref ref timeout-ms timeout-val)

deref 等同于这些读入器宏(reader macro): @ref / @agent / @var / @atom / @delay / @future / @promise

在事务中调用 deref 时,返回 ref 的事务值(in-transaction-value);在非事务情况下调用,则返回 ref 的最近一次提交值(most-recently-committed value).

应用于 varagentatom 时,返回它们的当前状态。

应用于 future 时,如果计算尚未完成,那么阻塞。

应用于 promise 时,如果该 promise 还没用 deliver 设置过值,那么阻塞。

timeout 参数的变种(variant)用于处理 futurepromise 这种可能会阻塞的引用(reference):当阻塞时长超过 timeout 毫秒,而引用还未有值可用时,返回 timeout-val 作为值。

查看源码

; 普通的 deref

user=> (def d (delay (+ 1 1)))
#'user/d

user=> (deref d)
2

user=> @d
2

; 带超时的 deref

user=> (def p (promise))
#'user/p

user=> (deref p 5000 nil)   ; 5 秒内没有可用值,就返回 nil
nil

dissoc

(dissoc map)
(dissoc map key)
(dissoc map key & keys)

dissoc 表示 dissociate 的意思。

dissoc 接受一个 Map ,以及任意个数的 key , 返回一个和传入 Map 类型相同的新 Map , 这个新 Map 不包含所有给定 key 的映射。

user=> (dissoc {:clojure "Rich" :python "Guido"})                               ; 没有传入 key
{:python "Guido", :clojure "Rich"}

user=> (dissoc {:clojure "Rich" :python "Guido"} :python)                       ; 传入单个 key
{:clojure "Rich"}

user=> (dissoc {:clojure "Rich" :python "Guido"} :ruby)                         ; 传入一个不存在于 Map 的 key
{:python "Guido", :clojure "Rich"}

user=> (dissoc {:clojure "Rich" :python "Guido" :ruby "Matz"} :python :ruby)    ; 传入多个 key
{:clojure "Rich"}

distinct

(distinct coll)

给定一个 coll ,返回一个无重复元素的惰性序列。

; 有重复元素的向量

user=> (distinct [1 2 1 2])
(1 2)


; 无重复元素的向量

user=> (distinct [1 2 3 4])
(1 2 3 4)

doall

(doall coll)
(doall n coll)

对于那些带副作用的函数所生成的惰性序列来说,只有当列表的某个元素被求值时,该元素的副作用才会被显现出来。

doall 使用 next 函数遍历整个序列,从而迫使惰性序列的副作用产生。

这个函数返回序列的首个元素作为结果,因此它需要在内存中保存整个序列。

自 Clojure 1.0 以来可用。

user=> (def one-to-three (range 3))
#'user/one-to-three

user=> (doall one-to-three)
(0 1 2)

user=> one-to-three
(0 1 2)

dorun

(dorun coll)
(dorun n coll)

对于那些带副作用的函数所生成的惰性序列来说,只有当列表的某个元素被求值时,该元素的副作用才会被显现出来。

dorun 使用 next 函数遍历整个序列,从而迫使惰性列表的副作用产生。

这个函数返回 nil ,而不是序列的首个元素。

自 Clojure 1.0 版本以来可用。

user=> (def infinity-hi (repeatedly #(println "hi")))
#'user/infinity-hi

user=> (dorun 5 infinity-hi)
hi
hi
hi
hi
hi
hi
nil

user=> (def one-to-ten (map println (range 10)))
#'user/one-to-ten

user=> (dorun one-to-ten)
0
1
2
3
4
5
6
7
8
9
nil

doseq

(doseq seq-exprs & body)

使用和 for 宏一样的绑定和过滤器,反复执行 body (通常是为了产生副作用)。

返回 nil 而不是序列的首元素作为函数结果。

自 Clojure 1.0 版本以来可用。

user=> (doseq [i (range 10)] (prn i))
0
1
2
3
4
5
6
7
8
9
nil

empty?

(empty? coll)

如果 coll 中不包含任何元素,那么返回 true , 效果等同于执行 (not (seq coll))

请使用惯用法 (seq x) 代替 (not (empty? x))

user=> (empty? '())
true

user=> (empty? nil)
true

user=> (empty? [1 2 3])
false

even?

(even? n)

当n是偶数时返回true,如果n不是一个整数则抛出异常

(even? 2)
true
(even? 1)
false

first

(first coll)

返回 coll 中的第一个元素。

传入的 coll 会被 seq 函数处理。

如果 collnil ,返回 nil

user=> (first nil)
nil

user=> (first [1 2 3])
1

user=> (first (list 1 2 3))
1

user=> (first {:clojure "Rich" :python "Guido" :ruby "Matz"})
[:python "Guido"]

file-seq

(file-seq dir)

返回一个惰性序列, 序列包含给定目录 dir 的整个目录树 (包括目录中的文件和目录中的文件夹及文件夹里的文件)。

dir 必须是一个 java.io.File 对象。

; 引入 file 函数,它可以根据路径名创建一个 File 对象
; 我们打开 /tmp 文件夹,并打印它的目录树

user=> (use '[clojure.java.io :only [file]])
nil

user=> (def tmp-folder (file "/tmp"))
#'user/tmp-folder

user=> (file-seq tmp-folder)
(#<File /tmp> #<File /tmp/.esd-1000> #<File /tmp/.esd-1000/socket> #<File /tmp/.Test-unix> #<File /tmp/mongodb-27017.sock> #<File /tmp/at-spi2> #<File /tmp/at-spi2/socket-1179-1131176229> #<File /tmp/at-spi2/socket-1268-1804289383> #<File /tmp/at-spi2/socket-1169-1369485920> #<File /tmp/mongodb-28017.sock> #<File /tmp/.X0-lock> #<File /tmp/.org.chromium.Chromium.NUsJHg> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonSocket> #<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonCookie> #<File /tmp/keyring-NwNaja> #<File /tmp/keyring-NwNaja/ssh> #<File /tmp/keyring-NwNaja/gpg> #<File /tmp/keyring-NwNaja/pkcs11> #<File /tmp/keyring-NwNaja/control> #<File /tmp/.ICE-unix> #<File /tmp/.ICE-unix/1303> #<File /tmp/cron.qpBNVU> #<File /tmp/pulse-PKdhtXMmr18n> #<File /tmp/ssh-ElvUhBgb1303> #<File /tmp/ssh-ElvUhBgb1303/agent.1303> #<File /tmp/.font-unix> #<File /tmp/pulse-397VI5uG1yhc> #<File /tmp/pulse-397VI5uG1yhc/pid> #<File /tmp/pulse-397VI5uG1yhc/native> #<File /tmp/pulse-397VI5uG1yhc/dbus-socket> #<File /tmp/hsperfdata_huangz> #<File /tmp/hsperfdata_huangz/9350> #<File /tmp/.X11-unix> #<File /tmp/.X11-unix/X0> #<File /tmp/.XIM-unix> #<File /tmp/.esd-120> #<File /tmp/pulse-T9RwKSB1FebW>)


; 使用 doseq 、 sort 和 println 函数
; 打印一个更美观的、经过排序的目录树

user=> (doseq [f (sort (file-seq tmp))]
         (println f))
#<File /tmp>
#<File /tmp/.ICE-unix>
#<File /tmp/.ICE-unix/1303>
#<File /tmp/.Test-unix>
#<File /tmp/.X0-lock>
#<File /tmp/.X11-unix>
#<File /tmp/.X11-unix/X0>
#<File /tmp/.XIM-unix>
#<File /tmp/.esd-1000>
#<File /tmp/.esd-1000/socket>
#<File /tmp/.esd-120>
#<File /tmp/.font-unix>
#<File /tmp/.org.chromium.Chromium.NUsJHg>
#<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonCookie>
#<File /tmp/.org.chromium.Chromium.NUsJHg/SingletonSocket>
#<File /tmp/at-spi2>
#<File /tmp/at-spi2/socket-1169-1369485920>
#<File /tmp/at-spi2/socket-1179-1131176229>
#<File /tmp/at-spi2/socket-1268-1804289383>
#<File /tmp/cron.qpBNVU>
#<File /tmp/hsperfdata_huangz>
#<File /tmp/hsperfdata_huangz/9350>
#<File /tmp/keyring-NwNaja>
#<File /tmp/keyring-NwNaja/control>
#<File /tmp/keyring-NwNaja/gpg>
#<File /tmp/keyring-NwNaja/pkcs11>
#<File /tmp/keyring-NwNaja/ssh>
#<File /tmp/mongodb-27017.sock>
#<File /tmp/mongodb-28017.sock>
#<File /tmp/pulse-397VI5uG1yhc>
#<File /tmp/pulse-397VI5uG1yhc/dbus-socket>
#<File /tmp/pulse-397VI5uG1yhc/native>
#<File /tmp/pulse-397VI5uG1yhc/pid>
#<File /tmp/pulse-PKdhtXMmr18n>
#<File /tmp/pulse-T9RwKSB1FebW>
#<File /tmp/ssh-ElvUhBgb1303>
#<File /tmp/ssh-ElvUhBgb1303/agent.1303>
nil

filter

(filter pred coll)

返回一个惰性序列, 序列中包含 coll 里所有 (pred item) 测试结果为 true 的项。

pred 必须是一个无副作用的函数。

; 过滤 0 - 9 中所有的奇数

user=> (filter even? (range 10))
(0 2 4 6 8)


; 过滤 0 - 9 中所有的偶数

user=> (filter odd? (range 10))
(1 3 5 7 9)


; 过滤 0 - 9 中所有小于 10086 的数,结果为空

user=> (filter #(> % 10086) (range 10))
()

fn

params => positional-params* 或者 positional-params* & next-param
positional-param => binding-form
next-param => binding-form
name => symbol

定义一个(匿名)函数。

user=> (fn greeting [name]                                          ; 创建匿名函数
           (str "Hello, " name " ."))
;#<user$eval1$greeting__2 user$eval1$greeting__2@616fde>

user=> ((fn greeting [name]                                         ; 应用匿名函数
           (str "hello, " name " ."))
        "moto")
"hello, moto ."

user=> ((fn greeting                                                ; 参数重载(arity overloading)
            ([name]
                (greeting "Hello" name))
            ([msg name]
                (str msg ", " name " .")))
        "moto")
"Hello, moto ."

user=> ((fn greeting                                                ; 接受不定数量参数的函数
            [name & others]
            (if (seq others)
                (str "Hello, " name " and others: " others " .")
                (str "Hello, " name " .")))
        "moto" "nokia" "apple")
"Hello, moto and others: (\"nokia\" \"apple\") ."

future

(future & body)

参数 body 接受一系列表达式,并返回一个 future 对象,使用 deref 或者 @ 可以对这个对象进行强迫求值。

future 对象会在另一个线程里对 body 进行求值,并将求值结果保存到缓存中,之后对这个 future 对象的所有强迫求值都会返回这个缓存值。

如果强迫求值时 body 的计算还没完成,那么调用者将被阻塞,直到计算完成,或者 deref 设置的过期时间到达为止。

; 普通的 future 调用

user=> (def f (future (+ 1 1)))
#'user/f

user=> f
#<core$future_call$reify__6110@fae040: 2>

user=> @f
2

; 一个停滞 5 秒的 future 调用

user=> @(future (println "start sleep") (Thread/sleep 5000) 10086)
start sleep
10086

; 一个带 timeout 的 deref 调用的例子,防止阻塞时间过长

user=> (deref (future (Thread/sleep 10000000000000000))
              1000
              "reach block timeout") ; 停滞 1 秒之后返回字符串值
"reach block timeout"

get

(get map key)
(get map key not-found)

返回 mapkey 所映射的值。

如果该 key 不存在,且给定了 not-found ,那么返回 not-found ,否则,返回 nil

查看源码

user=> (def clojure {:author "Rich Hickey"})
#'user/clojure

user=> (get clojure :author)
"Rich Hickey"

user=> (get clojure :version)       ; 无 not-found 参数
nil

user=> (get clojure :version 1.4)   ; 有 not-found 参数
1.4

if-let

(if-let bindings then)
(if-let bindings then else & oldform)
bindings => binding-form test

如果 test 为真,那么结合 binding-form 绑定,对 then 部分进行求值。

如果 test 为假,那么对 else 部分进行求值。

user=> (defn sum-all-even-number [all-number]
           (if-let [all-even-number (filter even? all-number)]
               (reduce + all-even-number)
               0))
#'user/sum-all-even-number

user=> (sum-all-even-number [1 2 3 4 5 6 7 8 9])
20  ; 2 + 4 + 6 + 8

user=> (sum-all-even-number [1 3 5 7 9])
0

if-not

(if-not test then)
(if-not test then else)

test 部分进行求值,如果结果为 false ,那么对 then 部分求值。

另一方面,如果 test 部分的求值结果为 true ,且 else 部分不为空,那么求值 else 部分;否则返回 nil

user=> (if-not false :then-part :else-part)
:then-part

user=> (if-not true :then-part)
nil

user=> (if-not true :then-part :else-part)
:else-part

import

(import & import-symbols-or-lists)

import-list => (package-symbol class-name-symbols*)

对于 class-name-symbols 中的每个 name 来说, 将名字为 package.name 的类添加到当前 namespace 当中。

可以在 ns 宏中通过 :import 来调用这个函数。

user=> (import java.util.Date)                      ; 载入单个类
java.util.Date

user=> (str (Date.))
"Wed Jun 20 23:18:42 CST 2012"

user=> (import '(java.util Date Calendar)           ; 载入多个类
               '(java.net URI ServerSocket))
java.net.ServerSocket

user=> (ns foo.bar                                  ; 在 ns 宏中使用
           (:import (java.util Date Calendar)
                    (java.net URI ServerSocket)))
java.net.ServerSocket

into

(into to from)

将from-coll中的所有元素合并至to-coll并返回结果

user=> (into (sorted-map) [ [:a 1] [:c 3] [:b 2] ] )
{:a 1, :b 2, :c 3}
user=> (into (sorted-map) [ {:a 1} {:c 3} {:b 2} ] )
{:a 1, :b 2, :c 3}

iterate

(iterate f x)

返回一个惰性序列, 序列元素的值为 x(f x)(f (f x))(f (f (f x))) , 诸如此类。

函数 f 必须是无副作用的。

; 生成一个计算所有正整数的惰性序列

user=> (def z (iterate inc 1))
#'user/z


; 取出第一个和第二个正整数

user=> (nth z 0)
1

user=> (nth z 1)
2


; 取出前十个正整数

user=> (take 10 z)
(1 2 3 4 5 6 7 8 9 10)

keep-indexed

(keep-indexed f coll)

对于 coll 中的每个项 item , 以及 item 对应的索引下标 index(keep-indexed f coll) 返回一个惰性序列, 序列中包含 (f index item)nil 之外的所有计算结果。

因为带副作用的函数会返回与计算结果无关的虚假值, 因此,为了确保虚假值不会混进 keep-indexed 所生成的惰性序列中, f 必须是一个无副作用的函数。

; 返回 0 - 9 内所有排序位置(index)为偶数的数字

user=> (keep-indexed #(if (even? %1) %2 nil) (range 10))
(0 2 4 6 8)

keep

(keep f coll)

对于 coll 中的每个项 item(keep f coll) 返回一个惰性序列, 序列包含 (f item)nil 之外的所有计算结果。

因为带副作用的函数会返回与计算结果无关的虚假值, 因此,为了确保虚假值不会混进 keep 所生成的惰性序列中, f 必须是一个无副作用的函数。

user=> (keep inc [1 2 3])
(2 3 4)

; 将空的 collection 传给 seq 函数会返回 nil
; 可以根据这个性质来测试 keep
; 看它是否真的会省略等于 nil 的值

user=> (seq [])
nil

user=> (keep seq (list [1 2 3] [] [4 5 6]))
((1 2 3) (4 5 6))

key

(key e)

返回map的键集合

::
(map key {:a 1,:b 2}) (:a :b)

keys

(keys map)

返回一个序列,序列里包含给定 map 的所有键(key)。

; 空 Map

user=> (keys {})
nil

; 非空 Map

user=> (keys {:python "Guido" :clojure "Rich" :ruby "Matz"})
(:python :ruby :clojure)

letfn

(letfn fnspecs & body)
fnspecs ==> (fname [params*] exprs) 或者 (fname ([params*] exprs)+)

使用一个函数体 body ,以及一个带有函数规格(specs)的向量 fnspecs , 将向量里的名字和相应的函数进行绑定。

向量里的名字在函数定义中,还有函数体内,都是可见的。

user=> (letfn [(twice [x]
                  (* x 2))
               (six-times [y]
                  (* 3 (twice y)))]
           (println "Twice 15 = " (twice 15))
           (println "Six times 15 = " (six-times 15)))
Twice 15 = 30
Six times 15 = 90
nil

;; 名字 twice 和 six-times 在离开 letfn 之后不可用

;user=> (twice 15)
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: twice in this context, compiling:(NO_SOURCE_PATH:7)

;user=> (six-times 15)
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: six-times in this context, compiling:(NO_SOURCE_PATH:8)

line-seq

(line-seq rdr)

返回一个惰性序列, 序列里包含从文件 rdr 中读出的所有字符串行。

rdr 必须是一个 java.io.BufferedReader 对象。

; 引入 reader 函数,它可以创建一个 java.io.BufferedReader 对象
; 读出 animal.txt 文件中的所有内容,之后再将文件联接关闭

user=> (use '[clojure.java.io :only [reader]])
nil

user=> (def animal (reader "animal.txt"))
#'user/animal

user=> (line-seq animal)
("dog" "cat" "monkey" "lion" "tiger" "dolphin")

user=> (.close animal)
nil


; 用 with-open 来自动处理文件的打开和关闭
; 并用更美观的方式打印 animal.txt 文件的内容

user=> (with-open [animal (reader "animal.txt")]
         (let [all-animal (line-seq animal)]
            (doseq [a all-animal]
                (println a))))
dog
cat
monkey
lion
tiger
dolphin
nil

map-indexed

(map-indexed f coll)

返回一个惰性序列, 序列里的第一个元素是将 0coll 的第一个元素应用到 f 所得出的值, 序列里的第二个元素是将 1coll 的第二个元素应用到 f 所得出的值。。。 以此类推,直到 coll 被处理完为止。

函数 f 应该接受两个参数:一个索引值,一个是 coll 的元素值。

查看源码

user=> (map-indexed (fn [idx item] [idx item]) "foobar")
([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])

user=> (map-indexed vector "foobar")    ; 另一种更简单的解法
([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])

map

(map f coll)
(map f c1 c2)
(map f c1 c2 c3)
(map f c1 c2 c3 & colls)

返回一个惰性序列, 序列的第一个元素是所有给定 collection 的第一个元素应用于函数 f 所得出的返回值, 序列的第二个元素是所有给定 collection 的第二个元素应用于函数 f 所得出的返回值。。。以此类推,一直到给定 collection 的其中一个被处理完为止。

当其中一个 collection 被处理完之后,其他 collection 的剩余元素会被忽略,因此结果序列的长度由给定 collection 中长度最短的那个决定。

函数 f 的参数个数应该和给定 collection 的数量一致。

查看源码

;; 处理单个 collection

user=> (range 10)
(0 1 2 3 4 5 6 7 8 9)

user=> (map inc (range 10))
(1 2 3 4 5 6 7 8 9 10)


;; 处理两个 collection

user=> (range 0 10)
(0 1 2 3 4 5 6 7 8 9)

user=> (reverse (range 0 10))
(9 8 7 6 5 4 3 2 1 0)

user=> (map #(+ %1 %2) (range 10) (reverse (range 10)))
(9 9 9 9 9 9 9 9 9 9)


;; 处理长度不同的两个 collection

user=> (map #(+ %1 %2) (range 10086) (reverse (range 10)))
(9 9 9 9 9 9 9 9 9 9)

mapcat

(mapcat f & colls)

等同于调用 (concat (map f colls))

查看源码

user=> (mapcat reverse [[3 2 1 0]
                        [6 5 4]
                        [9 8 7]])
(0 1 2 3 4 5 6 7 8 9)

max-key

(max-key f item1)
(max-key f item1 item2)
(max-key f item1 item2 & items)

将函数 f 应用到所有给定元素上,其中 (f item) 值最大的那个 item 被返回。

(f item) 的结果必须是数字值。

查看源码

user=> (max-key count "abc"
                      "abcd"
                      "a"
                      "abcdefg"
                      "aa")
"abcdefg"

merge

(merge & maps)

返回一个含有剩余项的map。 如果key在多个map中存在,后面的值(从左向右的顺序)会覆盖前面的值

::

user=> (merge {:a 1 :b 2 :c 3} {:b 9 :d 4}) {:d 4, :a 1, :b 9, :c 3}

user=> (merge {:a 1 :b 2 :c 3} {:b 9 :d 4} {:b 8 :d 3}) {:d 3, :c 3, :b 8, :a 1}

min-key

(min-key f item1)
(min-key f item1 item2)
(min-key f item1 item2 & items)

将函数 f 应用到所有给定元素上,其中 (f item) 值最小的那个 item 被返回。

(f item) 的结果必须是数字值。

查看源码

user=> (min-key count "aaaaaaa"
                      "bbbbbb"
                      "ccccccc"
                      "aa"
                      "dddddddd")
"aa"

odd?

(odd? n)

当n是奇数时返回true,如果n不是一个整数则抛出异常

(odd? 1)
true
(odd? 2)
false
(odd? 0)
false

partial

(partial f arg1)
(partial f arg1 arg2)
(partial f arg1 arg2 arg3)
(partial f arg1 arg2 arg3 & more)

partial 接受一个函数 f , 以及少于正常 f 所接受参数数量的参数, 并返回一个匿名函数。

当这个匿名函数被调用时, 传给它的附加参数(additional args)会和之前给定的参数一起, 传给函数 f

user=> (def three-times (partial * 3))
#'user/three-times

user=> (three-times 10)                     ; (* 3 10)
30

user=> (three-times 20)                     ; (* 3 20)
60

user=> (defn add-x-y-z [x y z]
           (+ x y z))
#'user/add-x-y-z

user=> (def add-y-z (partial add-x-y-z 0))  ; x = 0
#'user/add-y-z

user=> (def add-z (partial add-y-z 1))      ; y = 1
#'user/add-z

user=> (add-z 2)                            ; z = 2
3                                           ; (+ 0 1 2)

pcalls

(pcalls & fns)

并行计算 fns 中的无参数函数,并以惰性序列的形式返回它们的值。

查看源码

; 并行运行 3 个等待 3 秒的线程,共等待 3 秒
user=> (pcalls
         #(Thread/sleep 3000)
         #(Thread/sleep 3000)
         #(Thread/sleep 3000))
(nil nil nil)

注解

因为 pcallspvalues 的返回值都是惰性序列,因此,如果有一个非常耗时的表达式阻塞在其他一些表达式的前面,那么就算后面的这些表达式已经计算完了,它们也不能被返回。

以下是这样一个实例,在序列前面的三个元素,可以立即被返回,但是,后面的三个元素只有等待 (Thread/sleep 3000) 执行完毕之后,才会被返回,尽管它们早就在并发线程里被求值完了:

user=> (for [i (pvalues 1 2 3
                        (Thread/sleep 3000)
                        (do (println "eval 4") 4)
                        (do (println "eval 5") 5)
                        (do (println "eval 6") 6))
            ]
           (println i)
       )
(1
2
nil eval 5  ; 从 println 的输出可以看到
eval 4      ; 4 、 5 、 6 三个数已经被计算出来了,但还没办法返回
3
nil eval 6
nil         ; sleep 执行,停滞 3 秒
nil 4
nil 5
nil 6
nil nil)

pmap

(pmap f coll)
(pmap f coll & colls)

pmap 类似于 map ,唯一的不同是, pmap 对函数 f 的应用是并行的。

pmap 的返回值是半惰性的(semi-lazy): 并行计算总是发生在消耗(consumption)之前, 不过,计算结果只有在被需要时,才会被 realize 。

只有当 f 为计算密集型函数, 而且并行获得的性能提升足以抵消并行所需的协调消耗时, 才应该使用 pmap

查看源码

; 串行运行, 4 个元素,每个等待 3 秒,共等待 12 秒
user=> (time
         (dorun
           (map (fn [x] (Thread/sleep 3000))
                (range 4))))
"Elapsed time: 12000.767484 msecs"
nil

; 并行运行, 4 个元素,每个等待 3 秒,共等待 3 秒
user=> (time
         (dorun
           (pmap (fn [x] (Thread/sleep 3000))
                 (range 4))))
"Elapsed time: 3002.602211 msecs"
nil

promise

(promise)

试验版本,将来可能会出现改动。

返回一个 promise 对象,可以使用 deref 或者 @ 读取它的值,也可以使用 deliver 对它进行只能设置一次的赋值。

如果 promise 对象在使用 deliver 设置值之前,就被 deref 或者 @ 读取,那么调用者将被阻塞,直到 promise 对象有值,或者 deref 设置的超时时间到期为止。

deliver 设置值之后,对 promise 的每次 deref 或者 @ 都会不阻塞地返回 deliver 所设置的值。

查看源码

user=> (def p (promise))
#'user/p

user=> p
#<core$promise$reify__6153@bfb588: :pending>

; 对未有值的 promise 进行 deref
; 为了避免陷入无限阻塞,设置 5 秒的超时时间

user=> (deref p 5000 "reach timeout")
"reach timeout"

; 为 promise 设置值

user=> (deliver p 10086)
#<core$promise$reify__6153@bfb588: 10086>

user=> @p
10086

user=> p
#<core$promise$reify__6153@bfb588: 10086>

; 试试重复 deliver ?

user=> (deliver p 123123)
nil

user=> @p
10086

pvalues

(pvalues & exprs)

并行计算 exprs 中的表达式,并以惰性序列的形式返回它们的值。

查看源码

user=> (pvalues
         (Thread/sleep 3000)
         10086
         (Thread/sleep 3000)
         "hello moto")
(nil 10086 nil "hello moto")    ; 返回完整的计算结果需要 3 秒时间

注解

因为 pcallspvalues 的返回值都是惰性序列,因此,如果有一个非常耗时的表达式阻塞在其他一些表达式的前面,那么就算后面的这些表达式已经计算完了,它们也不能被返回。

以下是这样一个实例,在序列前面的三个元素,可以立即被返回,但是,后面的三个元素只有等待 (Thread/sleep 3000) 执行完毕之后,才会被返回,尽管它们早就在并发线程里被求值完了:

user=> (for [i (pvalues 1 2 3
                        (Thread/sleep 3000)
                        (do (println "eval 4") 4)
                        (do (println "eval 5") 5)
                        (do (println "eval 6") 6))
            ]
           (println i)
       )
(1
2
nil eval 5  ; 从 println 的输出可以看到
eval 4      ; 4 、 5 、 6 三个数已经被计算出来了,但还没办法返回
3
nil eval 6
nil         ; sleep 执行,停滞 3 秒
nil 4
nil 5
nil 6
nil nil)

range

(range)
(range end)
(range start end)
(range start end step)

返回一个惰性序列, 序列里包含从大于等于 start 到小于 end 区间内的所有数字(start <= numbers < end), 数字的步进以 step 指定。

默认情况下, start0step1 ,而 end 则为无限。

; 不指定任何参数,返回一个包含所有非负整数的惰性序列
; 0, 1, 2, 3 ...

user=> (take 3 (range))
(0 1 2)

user=> (take 10 (range))
(0 1 2 3 4 5 6 7 8 9)


; 只指定 end
; 返回大于等于 0 到小于 end 之内的所有整数

user=> (range 5)
(0 1 2 3 4)

user=> (range 10)
(0 1 2 3 4 5 6 7 8 9)


; 指定 start 和 end

user=> (range 5 10)
(5 6 7 8 9)

user=> (range 0 10)
(0 1 2 3 4 5 6 7 8 9)


; 指定 start 、 end 和 step
; 第一个惰性序列计算 2 到 20 内的所有偶数
; 第二个惰性序列计算 1 到 20 内的所有奇数

user=> (range 2 20 2)
(2 4 6 8 10 12 14 16 18)

user=> (range 1 20 2)
(1 3 5 7 9 11 13 15 17 19)

re-seq

(re-seq re s)

返回一个惰性序列, 序列里包含字符串 s 中所有匹配模式 re 的值, 匹配使用 java.util.regex.Matcher.find() 进行, 每个匹配值都经过 re-groups 处理。

; 查找字符串中的所有数字值

user=> (re-seq #"[0-9]+" "abs123def345ghi567")
("123" "345" "567")

realized?

(realized? x)

如果给定的 promisedelayfuture 或者 lazy-list 对象已经有值了,那么返回 true

查看源码

user=> (def d (delay (+ 1 1)))
#'user/d

user=> (realized? d)
false

user=> @d
2

user=> (realized? d)
true

reduce

(reduce f coll)
(reduce f val coll)

reduce 的行为由以下情况定义:

  • 没有给定 val
    • coll 为空:以无参数方式调用 f ,调用所得的值为返回值。
    • coll 只有一个元素:不调用 f ,直接将那个元素用作返回值。
    • coll 有多于一个元素:将 coll 的前两个元素应用到 f ,得到的结果再和 coll 的第三个元素一起应用到 f ,以此类推。
  • 有给定 val
    • coll 为空:不调用 f ,直接返回 val
    • coll 不为空:将 valcoll 的第一个元素应用到 f ,得到的结果再和 coll 的第二个元素一起应用到 f ,以此类推。

f 应该是一个接受两个参数的函数,如果处理的 coll 可能为空,那么它还应该能进行无参数调用。

查看源码

user=> (reduce + [])            ; coll 为空, + 返回无参数调用结果 0
0

user=> (reduce + (range 10))    ; coll 不为空
45

user=> (reduce + 0 (range 10))  ; coll 不为空,且给定 val
45

reductions

(reductions f coll)
(reductions f init coll)

返回一个惰性序列, 序列里包含计算 (reduce f coll) 所产生的所有中间结果。

如果给定了 init ,那么将它用作所有中间结果的初始值。

查看源码

user=> (reduce + (range 1 10))
45

user=> (reductions + (range 1 10))
(1 3 6 10 15 21 28 36 45)

user=> (reductions + 0 (range 1 10))    ; 注意 init 不止添加到序列头那么简单
(0 1 3 6 10 15 21 28 36 45)

user=> (reductions + 10 (range 1 10))   ; 它还作为每个中间值的初始化值
(10 11 13 16 20 25 31 38 46 55)

remove

(remove pred coll)

返回一个惰性序列, 序列中包含 coll 里所有 (pred item) 测试结果为 false 的项。

pred 必须是一个无副作用的函数。

; 删除 0 - 9 中的所有偶数

user=> (remove even? (range 10))
(1 3 5 7 9)


; 删除 0 - 9 中的所有奇数

user=> (remove odd? (range 10))
(0 2 4 6 8)


; 删除 0 - 9 中所有大于等于 0 的数字,结果为空

user=> (remove #(>= % 0) (range 10))
()

repeat

(repeat x)
(repeat n x)

返回一个包含 nx 的惰性序列。

如果不指定 n ,那么值 x 可以被包含无限次。

; 定义一个包含 10 个 "hi" 的惰性序列

user=> (def ten-hi (repeat 10 "hi"))
#'user/ten-hi

user=> ten-hi
("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi")


; 定义一个包含无限个 "hi" 的惰性序列

user=> (def infinite-hi (repeat "hi"))
#'user/infinite-hi

user=> (take 10 infinite-hi)
("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi")

user=> (take 20 infinite-hi)
("hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi" "hi")

repeatedly

(repeatedly f)
(repeatedly n f)

给定一个无参数的函数 f (通常带有副作用),返回一个调用 f 函数 n 次的惰性序列。

如果不指定参数 n ,那么函数 f 可以执行无限次。

; 测试函数

user=> (defn greet []
         "hi!")
#'user/greet


; 定义一个执行 10 次 greet 的惰性序列
; 并用 take 函数取出 5 个和 10 个 greet 的执行结果

user=> (def ten-greet (repeatedly 10 greet))
#'user/ten-greet

user=> (take 5 ten-greet)
("hi!" "hi!" "hi!" "hi!" "hi!")

user=> (take 10 ten-greet)
("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!")


; 试图取出 10086 个值,但 ten-greet 最多只返回 10 个值
; 说明取出的数量最多只能和 n 一样大

user=> (take 10086 ten-greet)
("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!")


; 定义一个执行无限次 greet 的惰性序列

user=> (def infinite-greet (repeatedly greet))
#'user/infinite-greet

user=> (take 10 infinite-greet)
("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!")

user=> (take 100 infinite-greet)
("hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!" "hi!")

reverse

(reverse coll)

逆序给定的 coll

这个操作不是惰性(lazy)的。

(user=>(reverse [1 2 3 4])
(4 3 2 1)

rseq

(rseq rev)

在常数时间内,返回 rev 的逆序序列。

rev 只能是向量或者 sorted-map 。

rev 为空时,返回 nil

; 空向量和空 sorted-map

user=> (rseq [])
nil

user=> (rseq (sorted-map))
nil


; 非空向量

user=> (rseq [1 2 3])
(3 2 1)


; 非空 sorted-map

user=> (def alpha (sorted-map :a "apple" :b "boy" :c "cat"))
#'user/alpha

user=> alpha
{:a "apple", :b "boy", :c "cat"}

user=> (rseq alpha)
([:c "cat"] [:b "boy"] [:a "apple"])


; 一些不能处理的情况

user=> (rseq (list 1 2 3))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Reversible  clojure.core/rseq (core.clj:1480)

user=> (rseq nil)
NullPointerException   clojure.core/rseq (core.clj:1480)

rsubseq

(rsubseq sc test key)
(rsubseq sc start-test start-key end-test end-key)

用法和 subseq 函数一样,但是返回的序列是逆序排序的。

等同于执行 (rseq (subseq sc test key)) 或者 (rseq (subseq sc start-test start-key end-test end-key))

; 测试数据

user=> (def numbers (sorted-map 1 "one" 2 "two" 3 "three" 4 "four" 5 "five"))
#'user/numbers

user=> numbers
{1 "one", 2 "two", 3 "three", 4 "four", 5 "five"}


; 过滤所有键小于 1 大于 4 的键-值对,并逆序地返回结果

user=> (rsubseq numbers >= 2 <= 4)
([4 "four"] [3 "three"] [2 "two"])


; 过滤所有键小于 2 的键-值对,并逆序地返回结果

user=> (rsubseq numbers > 2)
([5 "five"] [4 "four"] [3 "three"])

seq

(seq coll)

根据给定的 coll ,返回一个相应的序列。

coll 为空时,返回 nil

(sql nil) 也返回 nil

seq 函数也可以作用于字符串、 (带有引用类型的)原生 Java 数组, 以及任何实现了 iterable 接口的对象。

; 处理空向量和 nil

user=> (seq [])
nil

user=> (seq nil)
nil

; 处理非空向量、列表、 Map 和字符串

user=> (seq [1 2 3])
(1 2 3)

user=> (seq (list 1 2 3))
(1 2 3)

user=> (seq {:language "clojure" :creator "Rich Hickey"})
([:creator "Rich Hickey"] [:language "clojure"])

user=> (seq "hello world")
(\h \e \l \l \o \space \w \o \r \l \d)

shuffle

(shuffle coll)

返回对 coll 进行乱序排列之后得出的序列。

user=> (shuffle [1 2 3 4])
[4 1 3 2]

user=> (shuffle [1 2 3 4])
[1 3 2 4]

some

(some pred coll)

如果 coll 中有一个元素 x 能满足 (pred x) ,则返回``(pred x)``的值

如果 coll 中没有任何元素 x 能满足 (pred x) , 返回 nil

将一个集合用作 predsome 的一个惯用法: 比如说, (some #{:fred} coll):fred 存在于 coll 时返回 :fred , 如果不存在,就返回 nil

user=> (some #{:fred} [:fred :peter :jack])
:fred

user=> (some #{:mary} [:fred :peter :jack])
nil

user=> (some #(>= % 10) [1 3 5 7 9])            ; 查看是否有 >= 10 的值存在
nil

user=> (some #(>= % 5) [1 3 5 7 9])             ; 查看是否有 >= 5 的值存在
true

sort

(sort coll)
(sort comparator coll)

返回对 coll 进行排序之后得到的序列。

如果不指定 comparator , 那么默认使用 compare.comparator 必须实现 java.util.Comparator

user=> (sort [4 2 1 3])
(1 2 3 4)

user=> (sort >= [4 2 1 3])
(4 3 2 1)

user=> (sort <= [4 2 1 3])
(1 2 3 4)

subseq

(subseq sc test key)
(subseq sc start-test start-key end-test end-key)

过滤 sc 并返回一个序列,序列里的所有实体(entry)的键 ek 都必须符合条件 (true? (test (.. sc comparator (compare ek key)) 0))

如果没有任何实体符合条件,则返回 nil

参数 sc 必须是一个 sorted collection ,测试条件 test 可以是 <<=> 或者 >=

; 测试数据

user=> (def numbers (sorted-map 1 "one" 2 "two" 3 "three" 4 "four" 5 "five"))
#'user/numbers

user=> numbers
{1 "one", 2 "two", 3 "three", 4 "four", 5 "five"}


; 过滤所有键小于 3 的键-值对

user=> (subseq numbers >= 3)
([3 "three"] [4 "four"] [5 "five"])


; 过滤所有键小于 1 大于 4 的键-值对

user=> (subseq numbers >= 2 <= 4)
([2 "two"] [3 "three"] [4 "four"])


; 过滤所有键小于 10 的键-值对,返回 nil

user=> (subseq numbers >= 10)
nil

time

(time expr)

expr 进行求值,并打印求值所花费的时间。

expr 的值作为函数的返回值被返回。

查看源码

; 计算对比两个关键字 100 次所需的时间

user=> (time
         (dotimes [_ 100]
           (= :kw :kw)))
"Elapsed time: 0.23802 msecs"
nil

tree-seq

(tree-seq branch? children root)

返回一个惰性序列, 序列里包含通过深度优先遍历得出的一棵树中的所有节点。

branch? 函数接受一个参数, 通过向它传入一个节点,可以判断该节点是否拥有子节点。

children 函数接受一个参数, 通过向它传入一个节点,可以得到一个包含该节点的所有子节点的序列。

children 函数只会在那些 branch? 函数返回 true 的节点被调用。

root 是树的根节点。

; 函数 file-seq 用于列出一个文件夹的整个目录树
; 它是展示 tree-seq 用法的一个极好的例子

(defn file-seq
    [dir]
    (tree-seq
        (fn [^java.io.File f] (. f (isDirectory)))      ; 检查文件 f 是不是一个文件夹
        (fn [^java.io.File d] (seq (. d (listFiles))))  ; 如果是的话,就用 listFiles 方法遍历它
        dir))                                           ; 树的根节点是传入的文件夹

vals

(vals map)

返回一个序列,序列里包含给定 map 的所有值(value)。

; 空 Map

user=> (vals {})
nil

; 非空 Map

user=> (vals {:python "Guido" :clojure "Rich" :ruby "Matz"})
("Guido" "Matz" "Rich")

when-let

(when-let bindings & body)
bindings => binding-form test

如果 test 的值 value 为真,那么结合 binding-form 绑定,对 body 进行求值。

user=> (defn drop-one [coll]
           (when-let [s (seq coll)]
               (rest s)))
#'user/drop-one

user=> (drop-one [1 2 3])
(2 3)

when-not

(when-not test & body)

test 部分进行求值,如果结果为 false ,那么在一个隐式 do 的包围下对 body 进行求值。

user=> (when-not true
           (println "hello")
           (println "moto"))
nil

user=> (when-not false
           (println "hello")
           (println "moto"))
hello
moto
nil

with-open

(with-open bindings & body)

在绑定了名字 name 与初始值 inittry 表达式里面对 body 进行求值 并按照绑定时间从晚到早的顺序 在 finally 语句里面对每个 name 执行 (.close name) 调用

(ns io
  (:require [clojure.java.io :as io]))

(defn readLineByLine [file-name]
  (with-open [reader (io/reader file-name)]
    (doseq [line (line-seq reader)]
      (println line))))

(defn copyLineByLine [source target]
  (with-open [reader (io/reader source)
              writer (io/writer target)]
    (io/copy reader writer)))

xml-seq

(xml-seq root)

返回一个惰性序列,序列里包含一棵 xml 元素树。

xml 文件可以用 clojure.xml/parse 函数解释。

; 解释一个 xml 文件,并提取内容

user=> (require 'clojure.xml)
nil

user=> (def content (clojure.xml/parse "http://www.w3schools.com/xml/note.xml"))
#'user/content

; 根据 xml 内容,生成 xml 树

user=> (def tree (xml-seq content))
#'user/tree

user=> tree
({:tag :note, :attrs nil, :content [{:tag :to, :attrs nil, :content ["Tove"]} {:tag :from, :attrs nil, :content ["Jani"]} {:tag :heading, :attrs nil, :content ["Reminder"]} {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]}]} {:tag :to, :attrs nil, :content ["Tove"]} "Tove" {:tag :from, :attrs nil, :content ["Jani"]} "Jani" {:tag :heading, :attrs nil, :content ["Reminder"]} "Reminder" {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]} "Don't forget me this weekend!")


; 遍历树

user=> (nth tree 0)
{:tag :note, :attrs nil, :content [{:tag :to, :attrs nil, :content ["Tove"]} {:tag :from, :attrs nil, :content ["Jani"]} {:tag :heading, :attrs nil, :content ["Reminder"]} {:tag :body, :attrs nil, :content ["Don't forget me this weekend!"]}]}

user=> (nth tree 1)
{:tag :to, :attrs nil, :content ["Tove"]}

user=> (nth tree 2)
"Tove"

user=> (nth tree 3)
{:tag :from, :attrs nil, :content ["Jani"]}

user=> (nth tree 4)
"Jani"

zipmap

(zipmap keys vals)

返回一个含有键和相应值的map

user=> (zipmap [:a :b :c :d :e] [1 2 3 4 5])
{:e 5, :d 4, :c 3, :b 2, :a 1}

clojure.core.async

buffer

(buffer n)

返回一个大小固定为n的buffer,当buffer满了的时候,put操作会阻塞

user=> (def c (chan (buffer 3)))
#'user/c

clojure.data

diff

(diff a b)

递归比较a和b,返回一个tuple 结构如 [只在a中出现的元素 只在b中出现的元素 a和b中共同出现的元素]

比较规则: * a和b相等 返回[nil,nil,a] * Map键值相同值不同视为不同 * Set无法比较差异 * 所有的序列都被视为索引的关联集合,结果以向量的类型返回 * 所有东西(包含string)都视为原子且平等比较

(use 'clojure.data)
(def uno {:same "same", :different "one"})
(def dos {:same "same", :different "two", :onlyhere "whatever"})
(diff uno dos)
=> ({:different "one"} {:onlyhere "whatever", :different "two"} {:same "same"})
;;  {uno中出现的元素 } {           dos中出现的元素            } {两者均有的元素}

(diff {:a 1} {:a 1 :b 2})
=> (nil {:b 2} {:a 1})
;; 并没有只在第一个集合中存在的元素


(diff [1 2 3] [5 9 3 2 3 7])              ;;=> [[1 2] [5 9 nil 2 3 7] [nil nil 3]]
(diff (set [1 2 3]) (set [5 9 3 2 3 7]))  ;;=> [#{1}  #{7 9 5}        #{3 2}]

clojure.pprint

(A Pretty Printer for Clojure)

clojure.pprint 实现了一个灵活的工具,用于把clojure的数据结构输出成优雅易懂的格式。pretty printer最基本的使用方式,就是把代码中的 println 替换成 pprint。高级用户可以通过 the building blocks 来定制自己的输出格式。

pprint 对基础的数据提供了简单的格式,对 clojure source code 提供了专有的格式。其他更高级的格式,包括完全不像 clojure 惯用的数据格式的 XML ,JSON ,都可以通过自定义补丁来输出出来。

这个模块不仅包括 pprint, 也包括给 Common lisp 提供支持的 cl-format。因为 pprint 和 cl-format 需要共同作用,所以 pprint 支持非常简洁的自定义补丁。除此之外, pprint 也提供了 format function 作为 clojure 现有的标准 format function的一个替代。

欢迎查看 pprint 和 cl-format 的文档来获取更多的信息。

Added in Clojure version 1.2

cl-format

(cl-format writer format-in & args)

Common Lisp 兼容的格式输出的函数的实现。cl-format 的格式包括是输出到流里还是输出 成string都是通过不同的参数控制的。它支持极为复杂的机构化的数据。

Writer参数是java.io.Writer的一个实例,有的话输出成流,反之输出成String。format-in 用于格式控制。 args 指代数据将要被格式化输出的。

format control string 是通过格式化符号,标注怎么去把许多参数按不同的方式格式化的。 类似 String.format 的 dsl。

如果 writer 是控制,那么cl-format 返回 string,否则返回空值,输出到流里。

一个例子: (let [results [46 38 22]] (cl-format true “There ~[are~;is~:;are~]~:* ~d result~:p: ~{~d~^, ~}~%” (count results) results))

输出结果 out: There are 3 results: 46, 38, 22

详细的文档关于 format control string 在”Common Lisp the Language, 2nd edition”, Chapter 22 (available online at: http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/clm/node200.html#SECTION002633000000000000000) and in the Common Lisp HyperSpec at http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm

1 EXAMPLE

;; 一种格式化integer的方式.
;; 第一个参数把输出定向到 *out*
user=> (cl-format true "~5d\n" 3)
3
nil

;; 第一个参数nil或false回直接输出成sting
user=> (cl-format nil "~5d" 3)
"    3"

user=> (cl-format nil "Pad with leading zeros ~5,'0d" 3)
"Pad with leading zeros 00003"

user=> (cl-format nil "Pad with leading asterisks ~5,'*d" 3)
"Pad with leading asterisks ****3"


;; 如果有办法去描述一个左对齐的数在一个 formatString 里请标示在这理。
;; 这个任务在我看来,可以首先去 formatted 数成 String 然后再使用 <width>
规则加到原来的输出结果上。

user=> (cl-format nil "~15a" (cl-format nil "~:d" 1234567))
"1,234,567      "

user=> (cl-format nil "Always print the sign ~5@d" 3)
"Always print the sign    +3"

user=> (cl-format nil "Use comma group-separator every 3 digits ~12:d" 1234567)
"Use comma group-separator every 3 digits 1,234,567"

user=> (cl-format nil "decimal ~d  binary ~b octal ~o  hex ~x" 63 63 63 63)
"decimal 63  binary 111111  octal 77  hex 3f"

user=> (cl-format nil "base 7  ~7r  with width and zero pad  ~7,15,'0r" 63 63)
"base 7  120  with width and zero pad 000000000000120"

;; 在 cl-format 里不需要做任何转换  BigInt,
;; BigInteger, or BigDecimal.
user=> (cl-format nil "cl-format handle   BigInts ~15d" 12345678901234567890)
"cl-format handles BigInts
12345678901234567890"

user=> (cl-format nil "Be aware of auto-conversion  ~8,'0d  ~8,'0d" 2.4 -5/4)
"Be aware of auto-conversion  000002.4
0000-5/4"

;; 下面看起来可能像是一个bug,但是是被 Common Lisp HyperSpec 写在文档上的一种方法,如果你觉得这样写不爽,
;; 你也可以这样写 (format "%08d" -2)

user=> (cl-format nil "~8,'0d" -2)
"000000-2"

pp

(macro)

使用宏去调用 pprint 打印上一次的输出。等价于 (pprint *1)

添加于 Clojure 1.2 版本。

clojure.string

blank?

(blank? s)

如果 snil 、空字符串 "" 或者只包含空白的字符串,那么返回 true

user=> (clojure.string/blank? nil)
true

user=> (clojure.string/blank? "")
true

user=> (clojure.string/blank? "    ")
true

user=> (clojure.string/blank? "hello world")
false

reverse

(reverse s)

返回字符串 s 的逆序版本。

user=> (clojure.string/reverse "clojure")
"erujolc"

escape

(escape s cmap)

使用函数 cmap 对字符串 s 中的每个字符 ch 进行转义,并返回一个新字符串。

转义按照以下规则进行:

  • 如果 (cmap ch) 返回 nil ,那么将 ch 添加到新字符串
  • 如果 (cmap ch) 不为 nil ,那么将 (str (cmap ch)) 添加到新字符串。
user=> (clojure.string/escape "I want 1 < 2 as HTML, & other good things." {\< "&lt;" \> "&gt;" \& "&amp;"})
"I want 1 &lt; 2 as HTML, &amp; other good things."

replace

(replace s match replacement)

将字符串 s 中的所有 match 实例(instance)替换成 replacement

match / replacement 可以是以下组合:

  1. 字符串 / 字符串
  2. 字符 / 字符
  3. 模式(pattern) / 字符串或一个函数,其中函数的参数为模式所匹配的实例
; 组合 1 :用字符串替换字符串
; 将字符串里的子串 moto 替换成 google

user=> (clojure.string/replace "hello moto" "moto" "google")
"hello google"

; 组合 2 :用字符替换字符
; 将字符串的所有小写 o 替换成大写 O

user=> (clojure.string/replace "hello moto" "o" "O")
"hellO mOtO"

; 组合 3 :用字符串替换匹配模式的实例
; 将匹配 #"red" 模式的实例替换为 "blue"

user=> (clojure.string/replace "The color is red" #"red" "blue")
"The color is blue"

; 另一个组合 3 :用给定函数的返回值来替换匹配模式的实例
; 将字符串里的所有原音字母转换为大写

user=> (clojure.string/replace "The color is red" #"[aeiou]" clojure.string/upper-case)
"ThE cOlOr Is rEd"

replace-first

(replace-first s match replacement)

replace 函数的作用类似,但只替换 match 的第一个实例。

; 只有第一个匹配的原音 e 被转为大写字母了

user=> (clojure.string/replace-first "The color is red" #"[aeiou]" clojure.string/upper-case)
"ThE color is red"

capitalize

(capitalize s)

将字符串 s 的首个字符转换成大写,剩余的其他字符全部转换为小写。

user=> (clojure.string/capitalize "hello world")
"Hello world"

user=> (clojure.string/capitalize "HELLO WORLD")
"Hello world"

lower-case

(lower-case s)

将字符串 s 的所有字符转换为小写。

user=> (clojure.string/lower-case "hello moto")
"hello moto"

user=> (clojure.string/lower-case "HELLO MOTO")
"hello moto"

upper-case

(upper-case s)

将字符串 s 的所有字符转换为大写。

user=> (clojure.string/upper-case "hello moto")
"HELLO MOTO"

user=> (clojure.string/upper-case "HELLO MOTO")
"HELLO MOTO"

join

(join coll)
(join separator coll)

先使用 (seq coll)coll 转换为序列,然后返回一个包含序列里所有元素的字符串。

多个元素之间以一个可选的 separator 分隔开。

user=> (def fruit ["apple" "banana" "cherry"])
#'user/fruit

; 不使用 separator

user=> (clojure.string/join fruit)
"applebananacherry"

; 使用 ", " 作为 separator

user=> (clojure.string/join ", " fruit)
"apple, banana, cherry"

split

(split s re)
(split s re limit)

根据正则表达式 re ,对字符串 s 进行分割,结果所得的一个或多个字符串保存在一个向量里面。

可选的 limit 参数指定最大的分割次数。

这个函数不是惰性的。

; 分割 #"\r?\n" 是 clojure.string/split-lines 的定义

user=> (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n")
["hello" "moto" "again"]

; 带 limit 参数

user=> (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n" 1)
["hello\nmoto\r\nagain\r\n"]

user=>  (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n" 2)
["hello" "moto\r\nagain\r\n"]

user=>  (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n" 3)
["hello" "moto" "again\r\n"]

user=>  (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n" 4)
["hello" "moto" "again" ""]

user=>  (clojure.string/split "hello\nmoto\r\nagain\r\n" #"\r?\n" 5)
["hello" "moto" "again" ""]

split-lines

(split-lines s)

在字符串 s\n 或者 \r\n 处分割开。

user=> (clojure.string/split-lines "hello\nmoto\r\nagain\r\n")
["hello" "moto" "again"]

user=> (clojure.string/split-lines "no-new-lines")
["no-new-lines"]

user=> (clojure.string/split-lines "")
[""]

user=> (clojure.string/split-lines nil)
;NullPointerException   java.util.regex.Matcher.getTextLength (Matcher.java:1234)

trim

从字符串的两端移除空白。

user=> (clojure.string/trim "clojure")
"clojure"

user=> (clojure.string/trim "    clojure    ")
"clojure"

triml

(triml s)

移除字符串 s 左端的空白。

user=> (clojure.string/triml "    clojure    ")
"clojure    "

trimr

(trimr s)

移除字符串 s 右端的空白。

user=> (clojure.string/trimr "    clojure    ")
"    clojure"

trim-newline

(trim-newline s)

从字符串的末尾移除转行符 \n 和返回符 \r

类似于 Perl 的 chomp 函数。

user=> (clojure.string/trim-newline "test\n")
"test"

user=> (clojure.string/trim-newline "test\r")
"test"

user=> (clojure.string/trim-newline "test\n\r")
"test"

user=> (clojure.string/trim-newline "test\r\n")
"test"

; 只移除末尾的换行符

user=> (clojure.string/trim-newline "leading newline\n trailing newline\n")
"leading newline\n trailing newline"

clojure.set

difference

(difference s1)
(difference s1 s2)
(difference s1 s2 & sets)

返回集合 s1 和其余给定集合之间的差。

当只有一个参数时,返回该参数。

查看源码

user> (use 'clojure.set)
nil

; 单个集合

user> (difference #{:a :b :c})
#{:a :c :b}

user> (let [s #{:a :b :c}] (identical? s (difference s)))
true

; 两个集合

user> (difference #{:a :b :c} #{:a :b})
#{:c}

user> (difference #{:a :b :c} #{:a :b :c})
#{}

; 多个集合

user> (difference #{:a :b :c} #{:a} #{:b})
#{:c}

index

(index xrel ks)

index 类似于 SQL 中的 group by 操作:它把 xrel 中的成员按 ks 中列举的 key 的值进行分组。

其中, xrelks 都是序列(sequence)。 xrel 的成员是一个个 mapks 的成员是用于分组的 key

index 返回一个新 map ,新 mapkeyks 的成员作为 keyxrel 中每个 map 取到的不同值,新 mapvalue 是满足这些值的 xrel 中成员的集合。

查看源码

user> (use 'clojure.set)
nil

;; 处理 set

user> (def points #{{:x 0 :y 0} {:x 0 :y 1} {:x 1 :y 0}}) ;; 定义三个点
#'user/points

user> (index points [:x])       ;; group by x 坐标
{{:x 1} #{{:y 0, :x 1}},
 {:x 0} #{{:y 1, :x 0} {:y 0, :x 0}}}

user> (index points [:y :x])    ;; group by x 和 y 坐标
{{:x 1, :y 0} #{{:y 0, :x 1}},
 {:x 0, :y 0} #{{:y 0, :x 0}},
 {:x 0, :y 1} #{{:y 1, :x 0}}}

user> (index points [:z])       ;; group by 不存在的 z 坐标
{{} #{{:y 1, :x 0} {:y 0, :x 0} {:y 0, :x 1}}}

;; 还可以处理 vector

user> (def points-vec [{:x 0 :y 0} {:x 0 :y 1} {:x 1 :y 0}])
#'user/points-vec

user> (index points-vec [:x])
{{:x 1} #{{:y 0, :x 1}}, {:x 0} #{{:y 1, :x 0} {:y 0, :x 0}}}

intersection

(intersection s1)
(intersection s1 s2)
(intersection s1 s2 & sets)

计算输入集合的交集。

查看源码

user> (use 'clojure.set)
nil

user> (intersection #{1 2 3} #{3 4 5})
#{3}

user> (intersection #{1 2 3} #{2 3} #{3})
#{3}

join

(join xrel yrel)
(join xrel yrel km)

join 类似于 SQL 中的 join 操作:它对 xrelyrel 做关联操作。

xrelyrel 是两个序列,序列的每个成员都是一个 mapmap 的每个 key-value 对可以看做数据库表的字段以及对应的值。

如果提供了 km 参数,则按照 km 所列出的 key 进行关联。

查看源码

user> (use 'clojure.set)
nil

;; 处理 set

user> (def students             ;; 学生信息
        #{{:id 1 :name "Li Lei"}
          {:id 2 :name "Han Meimei"}})
#'user/students

user> (def score                ;; 学生成绩
        #{{:id 1 :score 60}
          {:id 2 :score 99}})
#'user/score

user> (join students score)     ;; 关联信息和成绩
#{{:score 99, :name "Han Meimei", :id 2}
  {:score 60, :name "Li Lei", :id 1}}

;; 处理 vector

user> (def score-vec
         [{:id 1 :score 60}
          {:id 2 :score 99}])
#'user/score

user> (join students score-vec)
#{{:score 99, :name "Han Meimei", :id 2}
  {:score 60, :name "Li Lei", :id 1}}

map-invert

(map-invert m)

反转一个 map ,将它原本的 value 映射为新 mapkey ,原本的 key 映射为新 mapvalue

注解

当多个 key 有同一个 value 时,新 map 只保留其中的一个作为 key

查看源码

user> (use 'clojure.set)
nil

user> (map-invert {:a 1 :b 2})
{2 :b, 1 :a}

user> (map-invert {:a 1 :b 2 :c 2}) ;; 两个 2 冲突,丢掉了 :c
{2 :b, 1 :a}

project

(project xrel ks)

对于 xrel 中的每个元素, project 的结果集合只包含那些 keyks 里出现过的元素为成员。

换一种说法来讲就是:将 xrel 的成员投影到 ks 指定的维度上。

查看源码

user> (use 'clojure.set)
nil

user> (def points           ;; 定义三个三维空间的点
  #{{:x 1 :y 0 :z 1}
    {:x 0 :y 1 :z 1}
    {:x 1 :y 1 :z 0}})
#'user/points

user> (project points [:x]) ;; 投影到 x 轴上
#{{:x 0} {:x 1}}            ;; 返回值是一个集合,所以计算结果中的两个 {:x 1} 只有一个被保留

user> (project points [:x :y])
#{{:y 1, :x 0} {:y 1, :x 1} {:y 0, :x 1}} ;; 投影到 x-y 平面上

rename

(rename xrel kmap)

xrel 中的元素的key改名,新旧名字的映射由 kmap 提供。

查看源码

user> (use 'clojure.set)
nil

user> (def students
  #{{:id 1 :name "Li Lei"}
    {:id 2 :name "Han Meimei"}})
#'user/students

user> (rename students {:id :student-id})
#{{:name "Han Meimei", :student-id 2} {:name "Li Lei", :student-id 1}}

rename-keys

(rename-keys map kmap)

map 中的 key 按照 kmap 提供的映射改名。

可以使用 array-map 类型的 kmap 来指定替换执行的顺序。

注意,替换可能造成 key 冲突,导致原来的 key-value 对被覆盖。

查看源码

user> (rename-keys {:id 1 :name "Li Lei"} {:id :new-id :name :new-name})
{:new-id 1, :new-name "Li Lei"}

; 改名造成 key 冲突,旧的 {:b 2} 被覆盖

user> (rename-keys {:a 1 :b 2} {:a :b})
{:b 1}

; 通过 array-map 指定替换执行的顺序

user> (rename-keys  {:a 1 :b 2 :c 3}  (array-map :a :tmp :b :a :tmp :b))
{:b 1, :a 2, :c 3}

select

(select pred xset)

返回 xset 中所有使 pred 为真的元素。

selectclojure.core/filter 类似,只是 select 的输入和输出都是 set

查看源码

user=> (use 'clojure.set)
nil

user=> (select even? #{1 2 3 4 5})
#{2 4}

user=> (select even? [1 2 3 4 5]) ;; 只能是set
ClassCastException clojure.lang.PersistentVector cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1420)

subset?

(subset? set1 set2)

判断 set1 是否 set2 的子集。

查看源码

user> (clojure.set/subset? #{:a :b} #{:a :b :c})
true

user> (clojure.set/subset? #{:a :b} #{:a :c :d})
false

user> (clojure.set/subset? #{} #{:a :c :d})
true

user> (clojure.set/subset? #{:a} #{:a})
true

superset?

(superset? set1 set2)

判断 set1 是否 set2 的超集。

查看源码

user> (clojure.set/superset? #{:a :b :c} #{:a :b})
true

user> (clojure.set/superset? #{:a :c :d} #{:a :b})
false

user> (clojure.set/superset? #{:a :b} #{:a :b})
true

user> (clojure.set/superset? #{:a :b} #{})
true

union

(union)
(union s1)
(union s1 s2)
(union s1 s2 & sets)

返回输入集合的并集。

查看源码

user> (clojure.set/union)
#{}

user> (clojure.set/union #{:a} #{:b :c})
#{:a :c :b}

user> (clojure.set/union #{:a :b} #{:b :c})
#{:a :c :b}

clojure.test

are

macro

(are argv expr & args)

通过以模板表达的方式检查多个断言(assertions)。关于模板的解释请查阅 clojure.template/do-template

;例子:
(are [x y] (= x y)
          2 (+ 1 1)
          4 (* 2 2))

;宏将展开为:
(do (is (= 2 (+ 1 1)))
    (is (= 4 (* 2 2))))

clojure.java.browse

browse-url

(browse-url url)

在浏览器中打开地址 url

查看源码

user=> (use 'clojure.java.browse)

user=> (browse-url "http://clojuredocs.org")

clojure.java.io

Coercions

clojure.java.io 内部定义的protocol,有 as-fileas-url 两个方法,clojure为多种类型实现了这个protocol。

copy

(copy input output & opts)

input 的内容拷贝到 output ,成功返回 nil ,失败抛出 IOException

input 可以是 java.io.InputStreamjava.io.Readerjava.io.Filebyte 数组,或者 java.lang.String 。当输入是 java.lang.String 的时候,是把字符串本身拷贝到输出。

output 可以是 java.io.OutputStreamjava.io.Writer 或者 java.io.File

opts 可以包含 :buffer-sizeencoding:buffer-size 默认1024。

除了自己打开的, copy 不会关闭任何流。

user> (use 'clojure.java.io)
nil
user> (copy "XXXXXX" (output-stream "/tmp/x"))
nil
user> (slurp "/tmp/x")
"XXXXXX"
user> (copy (file "/tmp/x") (output-stream "/tmp/xx"))
nil
user> (slurp "/tmp/x")
"XXXXXX"

IOFactory

clojure.java.io 内部定义的protocol,包含 make-readermake-writermake-input-streammake-out-stream 四个方法。这四个方法创建的都是带缓冲区的reader,writer或stream。

用户应该避免直接使用上述四个API,而是使用 readerwriterinput-streamoutput-stream

input-stream

(input-stream x & opts)

根据 x 创建一个 java.io.BufferedInputStream

x 可以是 java.io.InputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socketbyte 数组或者 char 数组 。

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

opts 定义创建选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (input-stream (java.io.File. "/tmp/x"))
;;#<BufferedInputStream java.io.BufferedInputStream@21606a56>
user> (input-stream (java.io.File. "/tmp/x") :encoding "UTF-8")
;;#<BufferedInputStream java.io.BufferedInputStream@3e347b11>

as-file

(as-file x)

接受一个 x 参数,返回一个 java.io.File 对象。 x 的类型可以是 java.lang.Stringjava.io.Filejava.net.URLjava.net.URI

x 的类型是 java.net.URLjava.net.URI 时,协议必须是 file

xnil 时,返回 nil

user> (use 'clojure.java.io)
nil
user> (.exists (as-file "/tmp"))
true
user> (.exists (as-file (java.io.File. "/tmp")))
true
user> (.exists (as-file (java.net.URL. "file:///tmp")))
true
user> (.exists (as-file (java.net.URL. "http://www.google.com")))
;;IllegalArgumentException Not a file: http://www.google.com  clojure.java.io/fn--8210 (io.clj:67)

as-relative-file

(as-relative-path x)

接受一个 x 参数,据此返回相对路径字符串。 x 的类型可以是 java.lang.Stringjava.io.Filejava.net.URLjava.net.URI ,跟 as-file 一样。

如果 x 不是用相对路径表示的,则抛出 IllegalArgumentException

user> (as-relative-path "./tmp")
"./tmp"
user> (as-relative-path "tmp")
"tmp"
user> (as-relative-path "/tmp")
;;IllegalArgumentException /tmp is not a relative path  clojure.java.io/as-relative-path (io.clj:404)
user> (as-relative-path (java.io.File. "tmp-file"))
"tmp-file"

as-url

(as-url x)

接受一个 x 参数,返回一个 java.net.URL 对象。 x 的类型可以是 java.lang.Stringjava.io.Filejava.net.URLjava.net.URI

x 的类型是 java.lang.String 时, x 必须是一个合法的URL。

xnil 时,返回 nil

如果提供了 km 参数,则按照 km 所列出的key进行join。

user> (use 'clojure.java.io)
nil
user> (as-url "http://baidu.com")
#<URL http://baidu.com>
user> (as-url (java.io.File. "/tmp"))
#<URL file:/tmp/>
user> (as-url (java.net.URI. "http://www.google.com"))
#<URL http://www.google.com>
user> (as-url "baidu.com")
;;MalformedURLException no protocol: baidu.com  java.net.URL.<init> (URL.java:567)

default-streams-impl

IOFactory 的默认实现,抛出 IllegalArgumentException

delete-file

(delete-file f & [silently])

删除文件 f 。如果有第二个参数,且为真值,则当文件不存在的时候,不抛出异常。

user> (use 'clojure.java.io)
nil
user> (spit "/tmp/x" "123") ;; 创建一个文件,写入内容
nil
user> (slurp "/tmp/x") ;; 验证一下,已经存在
"123"
user> (delete-file "/tmp/x") ;; 删掉它
true
user> (slurp "/tmp/x") ;; 没有了
;;FileNotFoundException /tmp/x (No such file or directory)  java.io.FileInputStream.open (FileInputStream.java:-2)
user> (delete-file "/tmp/x") ;; 抛异常
;;IOException Couldn't delete /tmp/x  clojure.java.io/delete-file (io.clj:425)
user> (delete-file "/tmp/x" true) ;; 安静删除
true

file

(file arg)
(file parent child)
(file parent child & more)

根据参数创建一个 java.io.File 对象。

如果只有一个参数 arg ,返回对应的 java.io.File 对象。

如果有多个参数,第一个参数 parent 作为根目录;后续参数作为每一层子目录或文件,且必须是用相对路径表示的。

parent , childmore 类型可以是 java.lang.Stringjava.io.Filejava.net.URL 或者 java.net.URI

user> (use 'clojure.java.io)
nil
user> (file "/tmp")
#<File /tmp>
user> (file "/tmp" "a" "b")
#<File /tmp/a/b>
user> (file "/tmp" "a" (java.io.File. "../b"))
#<File /tmp/a/../b>
user> (file (java.net.URL. "file:///tmp") "a" (java.io.File. "../b"))
#<File /tmp/a/../b>

make-input-stream

(make-input-stream x opts)

根据 x 创建一个 java.io.BufferedInputStream

x 可以是 java.io.BufferedInputStreamjava.io.InputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socket 或者 byte 数组。

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (make-input-stream "/tmp/x" {})
;;#<BufferedInputStream java.io.BufferedInputStream@3a7aa9f6>
user> (make-input-stream (java.io.File. "/tmp/x") {})
;;#<BufferedInputStream java.io.BufferedInputStream@df077d2>
user> (make-input-stream (java.io.File. "/tmp/NO_SUCH_FILE") {})
;;FileNotFoundException /tmp/NO_SUCH_FILE (No such file or directory)  java.io.FileInputStream.open (FileInputStream.java:-2)

make-output-stream

(make-output-stream x opts)

根据 x 创建 java.io.BufferedOutputStream

x 可以是 java.io.BufferOutputStreamjava.io.OutputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socket

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

xjava.net.URLjava.net.URI 时,协议必须是 file

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (make-output-stream "/tmp/x" {})
;;#<BufferedOutputStream java.io.BufferedOutputStream@5440bf04>
user> (make-output-stream (file "/tmp/x") {})
;;#<BufferedOutputStream java.io.BufferedOutputStream@4268d15>

make-parents

(make-parents f & more)

创建父目录,成功返回 true

fmore 可以是 java.lang.Stringjava.io.Filejava.net.URL 或者 java.net.URI

user> (use 'clojure.java.io)
user> (make-parents "/tmp/a/b/c/d") ;; 创建 /tmp/a/b/c/
true
user> (make-parents "/tmp/a/x/" "y" "z/") ;; 创建 /tmp/a/x/y
true

make-reader

(make-reader x opts)

根据 x 创建一个 java.io.BufferedReaderx 可以是 java.io.InputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socketbyte 数组或者 char 数组 。

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (make-reader "http://baidu.com" {})
;;#<BufferedReader java.io.BufferedReader@5994a1e9>

make-writer

(make-writer x opts)

跟据 x 构造 java.io.BufferedWriter

x 可以是 java.io.BufferOutputStreamjava.io.OutputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socket

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

xjava.net.URLjava.net.URI 时,协议必须是 file

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (make-writer (java.io.File. "/tmp/xxx") {})
;;#<BufferedWriter java.io.BufferedWriter@c92fa70>

output-stream

(output-stream x & opts)

根据 x 创建 java.io.BufferedOutputStream

x 可以是 java.io.BufferOutputStreamjava.io.OutputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socket

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

xjava.net.URLjava.net.URI 时,协议必须是 file

opt 定义创建选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (input-stream (as-file "/tmp/x"))
;;#<BufferedInputStream java.io.BufferedInputStream@49160709>
user> (input-stream (as-file "/tmp/x") :append true)
;;#<BufferedInputStream java.io.BufferedInputStream@7f6ce64e>

reader

(reader x & opts)

根据 x 创建一个 java.io.BufferedReaderx 可以是 java.io.InputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socketbyte 数组或者 char 数组 。

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (reader "http://baidu.com" :encoding "GB2312")
;;#<BufferedReader java.io.BufferedReader@620a9239>

resource

(resource n)
(resource n loader)

是用 ClassLoader 加载资源文件,返回 java.net.URL 对象。如果找不到资源文件,返回 nil

n 是资源名字字符串。 如果要使用特定的 ClassLoader ,需要使用 loader 参数。

user> (use 'clojure.java.io)
nil
user> (resource "project.clj")
#<URL jar:file:/Users/xiafei/.lein/self-installs/leiningen-2.0.0-preview10-standalone.jar!/project.clj>

writer

(writer x & opts)

跟据 x 构造 java.io.BufferedWriter

x 可以是 java.io.BufferOutputStreamjava.io.OutputStreamjava.io.Filejava.net.URLjava.net.URIjava.lang.Stringjava.net.Socket

xjava.lang.String 时,会先尝试把 x 解释成 java.net.URL ,如果失败,则是 java.io.File

xjava.net.URLjava.net.URI 时,协议必须是 file

opt 是一个map,定义选项,key可以是 :append:encoding

user> (use 'clojure.java.io)
nil
user> (writer (java.net.URL. "file:///tmp/x") :append true)
;;#<BufferedWriter java.io.BufferedWriter@7274187a>

clojure.java.javadoc

add-local-javadoc

(add-local-javadoc path)

将路径 path 添加到本地 javadoc 的路径列表中。

查看源码

add-remote-javadoc

(add-remote-javadoc package-prefix url)

添加路径 url 到远程 javadoc 路径的列表, package-prefix 是 URL 对应的 javadoc 的包名的开始部分。

查看源码

user=> (use 'clojure.java.javadoc)
nil

user=> (add-remote-javadoc "org.apache.commons.csv." "http://commons.apache.org/proper/commons-csv/apidocs/index.html")
{"java." "http://java.sun.com/javase/6/docs/api/", "javax." "http://java.sun.com/javase/6/docs/api/", "org.apache.commons.codec." "http://commons.apache.org/codec/api-release/", "org.apache.commons.csv." "http://commons.apache.org/proper/commons-csv/apidocs/index.html", "org.apache.commons.io." "http://commons.apache.org/io/api-release/", "org.apache.commons.lang." "http://commons.apache.org/lang/api-release/", "org.ietf.jgss." "http://java.sun.com/javase/6/docs/api/", "org.omg." "http://java.sun.com/javase/6/docs/api/", "org.w3c.dom." "http://java.sun.com/javase/6/docs/api/", "org.xml.sax." "http://java.sun.com/javase/6/docs/api/"}

javadoc

(javadoc class-or-object)

使用阅览器打开 class-or-object 参数的相关 javadoc 文档。

优先打开本地文档( *local-javadocs* ), 其次才是远程文档( *remote-javadoc* )。

查看源码

user=> (use 'clojure.java.javadoc)
nil

user=> (javadoc String)
"http://java.sun.com/javase/6/docs/api/java/lang/String.html"

user=> (javadoc (java.util.Date.))
"http://java.sun.com/javase/6/docs/api/java/util/Date.html"

clojure.java.shell

sh

(sh & args)

传递给出的字符串到 Runtime.exec() 来启动一个子进程。

选项有:

  • :in :给出下列合法的输入源给 clojure.java.io/copy , 比如, InputStream , Reader , File , byte[] 或者 String , 来提供子进程的标准输入(stdin)。
  • :in-enc :给出一个字符串。作为字符的编码名(比如, UTF-8 或者 ISO-8859-1)来转换 :in 中给定的字符串的编码,默认是 UTF-8 。 如果 :in 给出的字节数组(byte array), 那么它不会被解码,这个选项会被忽略。
  • :out-enc :选项可以是一个 :bytes 或者一个 String , 如果给出的是一个 String , 它会被当作一个字符编码的名字,(比如, UTF-8 或者 ISO-8859-1)来转换子进程的标准输出的字符串编码,如果给出的是 :bytes , 子进程的标准输出会被存储到一个字节数组返回,默认是 UTF-8
  • :env :用一个 map 重载进程的环境变量(env),如果你是一个受虐狂,你可以用一个 String[]
  • :dir :用一个 String 或者 java.io.File 重载进程工作目录(dir)

你可以用 with-sh-env 或者 with-sh-dir 绑定 :env 或者 :dir 到多个操作。

sh 返回一个 map :

  • :exit :子进程的返回码
  • :out :子进程的标准输出(stdout)(byte[] 或者 String
  • :err :子进程的标准错误(stderr)(用平台默认的编码的 String

查看源码

user=> (use '[clojure.java.shell :only [sh]])

;; Note: The actual output you see from a command like this will look messier.
;; The output below has had all newline characters replaced with line
;; breaks.  You would see a big long string with \n characters in the middle.
user=> (sh "ls" "-aul")

{:exit 0,
 :out "total 64
drwxr-xr-x  11 zkim  staff    374 Jul  5 13:21 .
drwxr-xr-x  25 zkim  staff    850 Jul  5 13:02 ..
drwxr-xr-x  12 zkim  staff    408 Jul  5 13:02 .git
-rw-r--r--   1 zkim  staff     13 Jul  5 13:02 .gitignore
-rw-r--r--   1 zkim  staff  12638 Jul  5 13:02 LICENSE.html
-rw-r--r--   1 zkim  staff   4092 Jul  5 13:02 README.md
drwxr-xr-x   2 zkim  staff     68 Jul  5 13:15 classes
drwxr-xr-x   5 zkim  staff    170 Jul  5 13:15 lib
-rw-r--r--@  1 zkim  staff   3396 Jul  5 13:03 pom.xml
-rw-r--r--@  1 zkim  staff    367 Jul  5 13:15 project.clj
drwxr-xr-x   4 zkim  staff    136 Jul  5 13:15 src
", :err ""}


user=> (use '[clojure.java.shell :only [sh]])

user=> (println (:out (sh "cowsay" "Printing a command-line output")))

 _________________________________
< Printing a command-line output. >
 ---------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

nil




user=> (use '[clojure.java.shell :only [sh]])
nil

;; note that the options, like :in, have to go at the end of arglist
;; advantage of piping-in thru stdin is less need for quoting/escaping
user=> (println (:out (sh "cat" "-" :in "Printing input from stdin with funny chars like ' \" $@ & ")))
Printing input from stdin with funny chars like ' " $@ &
nil

with-sh-dir

(with-sh-dir dir & forms)

设置 sh 函数所使用的目录, 详情请参见 sh 函数的文档

查看源码

with-sh-env

(with-sh-env env & forms)

设置 sh 函数所使用的环境变量, 详情请参见 sh 函数的文档

查看源码

clojure.xml

parse

(parse s)

(parse s startparse)

解析并加载源 ss 可以是一个文件, InputStream ,或者一个代表 URL 的字符串。

函数返回一棵 xml/element 类型的 struct-map 树, struct-map 中包含键 :tag:attrs:content , 以及访问函数 tagattrscontent

startparse 用于指定解释所使用的解释器, 这个参数的值应该是一个函数: 函数接受一个源(source)和一个内容处理器(ContentHandler)作为参数, 并返回一个解释器作为函数的返回值。

查看源码

(require '[clojure.xml :as xml]
 '[clojure.zip :as zip])

;;convenience function, first sawn at nakkaya.com later in clj.zip src
(defn zip-str [s]
  (zip/xml-zip (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))))

;;parse from xml-strings to internal xml representation
(zip-str "<a href='nakkaya.com'/>")
=>
[{:tag :a, :attrs {:href "nakkaya.com"}, :content nil} nil]

;;root can be rendered with xml/emit-element
(xml/emit-element (zip/root [{:tag :a, :attrs {:href "nakkaya.com"}, :content nil} nil]))
=>
<a href='nakkaya.com'/>
;;printed (to assure it's not lazy and performance), can be catched to string variable with with-out-str

clojure.repl

apropos

(apropos str-or-pattern)

返回当前命名空间下所有与给定正则表达式或者字符串(str-or-pattern)相匹配的定义的序列

user=> (apropos "temp")
()

user=> (require 'clojure.template)
nil

user=> (apropos "temp")
(apply-template do-template)

;; 使用正则表达式
user=> (apropos #".*-temp*")
(apply-template do-template)

dir

(dir nsname)

分类打印出给定命名空间下的公共Var对象

user=> (require 'clojure.string 'clojure.repl)

user=> (clojure.repl/dir clojure.string)
blank?
capitalize
escape
join
lower-case
replace
replace-first
reverse
split
split-lines
trim
trim-newline
triml
trimr
upper-case

dir-fn

(dir-fn ns)

返回一个有序序列,该序列包括给定命名空间(ns)的公共Var对象。

user=> (require 'clojure.repl 'clojure.string)

user=> (pprint (clojure.repl/dir-fn 'clojure.string))
(blank?
 capitalize
 escape
 join
 lower-case
 replace
 replace-first
 reverse
 split
 split-lines
 trim
 trim-newline
 triml
 trimr
 upper-case)
nil

doc

(doc name)

打印出某个Var对象或者special form的文档信息

=> (doc map)
;; prints in console:
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
  Returns a lazy sequence consisting of the result of applying f to the
  set of first items of each coll, followed by applying f to the set
  of second items in each coll, until any one of the colls is
  exhausted.  Any remaining items in other colls are ignored. Function
  f should accept number-of-colls arguments.

=> (doc clojure.core)
-------------------------
clojure.core
  Fundamental library of the Clojure language

find-doc

(find-doc re-string-or-pattern)

如果某个Var对象的名字或者文档能与给定字符串或者正则表达式相匹配,那么打印该Var对象的文档信息。

user=> (find-doc "data structure")

-------------------------
clojure.core/eval
([form])
  Evaluates the form data structure (not text!) and returns the result.
-------------------------
clojure.core/ifn?
([x])
  Returns true if x implements IFn. Note that many data structures
  (e.g. sets and maps) implement IFn
    user=> (require 'clojure.string 'clojure.repl)
-------------------------
........

pst

(pst)
(pst e-or-depth)
(pst e depth)

英文全称为print stack trace

打印出最近一次被REPL捕获的异常信息

user=> (/ 1 0)
;; ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:156)

user=> (pst)
;; ArithmeticException Divide by zero
;;    clojure.lang.Numbers.divide (Numbers.java:156)
;;    clojure.lang.Numbers.divide (Numbers.java:3691)
;;    user/eval13 (NO_SOURCE_FILE:7)
;;    clojure.lang.Compiler.eval (Compiler.java:6619)
;;    clojure.lang.Compiler.eval (Compiler.java:6582)
;;    clojure.core/eval (core.clj:2852)
;;    clojure.main/repl/read-eval-print--6588/fn--6591 (main.clj:259)
;;    clojure.main/repl/read-eval-print--6588 (main.clj:259)
;;    clojure.main/repl/fn--6597 (main.clj:277)
;;    clojure.main/repl (main.clj:277)
;;    clojure.main/repl-opt (main.clj:343)
;;    clojure.main/main (main.clj:441)
nil

参考资料

Clojure 官方文档: clojure.org/documentation

Clojure API 手册: clojure.github.com/clojure

Clojure Cheat Sheet: clojure.org/cheatsheet

ClojureDocs ,由社区驱动的,带代码示例的 API 手册: clojuredocs.org