Skip to content

Latest commit

 

History

History
1437 lines (890 loc) · 32.2 KB

clojure.core.rst

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)

返回一个包含 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")

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)

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

将一个集合用作 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

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

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