Skip to content

Latest commit

 

History

History
1437 lines (890 loc) · 32.2 KB

File metadata and controls

1437 lines (890 loc) · 32.2 KB

clojure.core

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)

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)

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

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"])

vals

(vals map)

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

; 空 Map

user=> (vals {})
nil

; 非空 Map

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

keys

(keys map)

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

; 空 Map

user=> (keys {})
nil

; 非空 Map

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

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!")

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)

repeat

(repeat x)
(repeat n x)

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

如果不指定 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")

range

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

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

默认情况下, start 为 0 , step 为 1 ,而 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)

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))

distinct

(distinct coll)

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

; 有重复元素的向量

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


; 无重复元素的向量

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

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))
()

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))
()

re-seq

(re-seq re s)

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

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

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

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

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

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))                                           ; 树的根节点是传入的文件夹

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"

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)

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)

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)

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)

reverse

(reverse coll)

逆序给定的 coll 。

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

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

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)

shuffle

(shuffle coll)

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

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

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

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

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

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

some

(some pred coll)

返回 coll 中第一个满足条件 (pred x) 的值 x 。

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

将一个集合用作 pred 是 some 的一个惯用法: 比如说, (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

first

(first coll)

返回 coll 中的第一个元素。

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

如果 coll 为 nil ,返回 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"]

next

(next coll)

返回 coll 除了第一个元素之外,余下的其他全部元素。

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

如果 coll 除了 (first coll) 之外, 没有其他别的元素,那么返回 nil 。

user=> (next nil)
nil

user=> (next [1])
nil

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

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

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

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"

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\") ."

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)

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)

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"

complement

(complement f)

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

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

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

user=> (f)
hello
false

user=> ((complement f))
hello
true

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

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)

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"}

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