Skip to main content
 Web开发网 » 操作系统 » linux系统

Clojure 一切皆序列

2021年10月14日5940百度已收录

Clojure 一切皆序列  第1张

程序操作的对象是数据。

在最底层,程序面对的是字符串、列表、向量、映射表、集合和树这样的数据结构。

在Clojure中,所有这些数据结构都可以通过同一个抽象概念来访问:序列。

序列(seq,发音“seek”)是一种逻辑上的列表。说它是逻辑上的,是因为Clojure的序列,并没有被捆绑在某种列表的实现细节上(比如说Lisp的conscell,列表构造单元)。相反,序列是一种抽象,可以用于任何地方。

可被视为序列的容器,被称为可序化的(seq-able,发音“SEEKa-bull”)。

可序化的容器。

● 所有的Clojure容器

● 所有的Java容器

● Java数组和字符串

● 正则表达式的匹配结果

● 目录结构

● 输入/输出流

● XML树

一切皆序列每一种聚合的(aggregate)数据结构,在Clojure中都能被视为序列。

序列具有三大核心能力。

● 能得到序列的第一个元素。

Clojure 一切皆序列  第2张

如果参数aseq是空的或者是nil,则first返回nil。

● 能获取第一个元素后面的一切东西,换句话说,就是序列的剩余(rest)部分。

Clojure 一切皆序列  第3张

如果没有更多的项,则rest返回一个空序列(而不是nil)。

● 可以通过向现有序列的前端添加元素,来创建一个新的序列。cons。

Clojure 一切皆序列  第4张

在 Clojure 内部,这三个功能是在 Java 接口 clojure.lang.ISeq 中声明的。在阅读Clojure代码时尤其要记住这一点,名称ISeq常被用来与seq进行互换。

seq函数会返回一个序列,该序列源自任何一个可序化的其他容器。

Clojure 一切皆序列  第5张

如果coll是空的或者是nil,则seq返回nil。next函数也会返回一个序列,该序列由除第一个元素以外的其他所有元素组成。

Clojure 一切皆序列  第6张

(next aseq)等价于 (seq (rest aseq))。

Clojure 一切皆序列  第7张

澄清rest和next

序列函数能作用于列表

Clojure 一切皆序列  第8张

序列函数能作用于列表向量

Clojure 一切皆序列  第9张

对向量使用rest或cons时,得到的结果是一个序列,而非向量。

Clojure 一切皆序列  第10张

类名末尾的那个$ChunkedSeq是Java为了对内联类进行名称改编,而采取的方式。从某个特定容器类型产生出来的序列,总会被实现为ChunkedSeq,并内联到原始容器类里(此例中是PersistentVector)。

Cons的起源Clojure序列是一种以Lisp实体列表为基础的抽象概念。

函数cons是construct的简写。序列是不可变的。

cons给序列添加了一个元素,但更准确的说法还是cons构建了一个新的序列。这个新序列与原来的那个相似,只不过新增了一个元素。

序列函数能作用于映射表

Clojure 一切皆序列  第11张

序列函数能作用于集合

Clojure 一切皆序列  第12张

映射表和集合的遍历顺序是稳定的,但这个顺序取决于具体的实现细节,所以不应该依赖它。

集合的元素不一定会依照你存放的顺序返回。

Clojure 一切皆序列  第13张

要可靠的顺序:

Clojure 一切皆序列  第14张

sorted-set会依据自然顺序对值进行排序。

Clojure 一切皆序列  第15张

映射表键值对也不一定按照你存放的顺序返回。

Clojure 一切皆序列  第16张

使用sorted-map来创建一个有序的映射表。

Clojure 一切皆序列  第17张

sorted-map也不会按照存放的顺序返回,但它会根据键来进行排序。

Clojure 一切皆序列  第18张

为什么执行函数时传入的是向量,却返回了列表?无论输入的是什么,序列函数返回的总是序列。

Clojure 一切皆序列  第19张

(rest [1 2 3])的结果是某种类型的序列,而非列表。

当要求REPL显示一个序列时,它仅知道那是一个序列。这个序列究竟是用哪种类型的容器构建的,REPL一无所知。因此,它干脆就采用相同的方式来打印所有序列:遍历整个序列,并将其作为一个列表打印出来。

conj和into

Clojure 一切皆序列  第20张

conj 会向容器添加一个或是多个元素,into 则会把容器中的所有元素添加至另一个容器。添加数据时,conj和into都会根据底层数据结构的特点选取最高效的插入点。对于列表而言,conj和into会在其前端进行添加。

Clojure 一切皆序列  第21张

对于向量,conj和into则会把元素添加至末尾。

Clojure 一切皆序列  第22张

conj(及其相关函数)会针对底层数据结构高效的进行操作,所以总是能编写既高效又与底层特定实现完全解耦的代码。

Clojure 序列库特别适合于那些庞大的(甚至是无限的)序列。

绝大多数 Clojure序列都是惰性的:只有当确实需要时,它们才真正的把元素生成出来。

因此,Clojure序列函数能够处理那些无法驻留在内存中的超大序列。

Clojure序列是不可变的:它们永远都不会发生变化。Clojure序列在并发访问时是安全的。

● triple会把序列中的每个元素分别乘与三。

● triple 接受一个序列,并返回一个新的序列,这个新序列的每个元素,都是原序列元素的三倍。

后一个版本具体并且准确。前者是更容易阅读一些,但可能会导致这个错误的印象:序列实际上改变了。莫要被愚弄了,序列永不改变。

评论列表暂无评论
发表评论
微信