nyb*_*bon 31 collections abstraction clojure
我是一名Java程序员,也是Clojure的新手.从不同的地方,我看到序列和集合在不同的情况下使用.但是,我不知道他们之间究竟有什么区别.
举个例子:
1)在Clojure的序列文档中:
The Seq interface
(first coll)
Returns the first item in the collection.
Calls seq on its argument. If coll is nil, returns nil.
(rest coll)
Returns a sequence of the items after the first. Calls seq on its argument.
If there are no more items, returns a logical sequence for which seq returns nil.
(cons item seq)
Returns a new seq where item is the first element and seq is the rest.
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,在描述Seq接口时,前两个函数(first/rest)使用coll,这似乎表明这是一个集合,而cons函数使用seq似乎表明这是一个序列.
2)有函数调用coll?和seq?可被用来测试一个值是否集合或序列.很明显,收集和顺序是不同的.
3)在Clojure关于" 收藏 " 的文件中,有人说:
由于集合支持seq函数,因此所有序列函数都可以与任何集合一起使用
这是否意味着所有集合都是序列?
(coll? [1 2 3]) ; => true
(seq? [1 2 3]) ; => false
Run Code Online (Sandbox Code Playgroud)
上面的代码告诉我它不是这种情况,因为它[1 2 3]是一个集合,但不是一个序列.
我认为这对于Clojure来说是一个非常基本的问题,但我无法找到一个地方清楚地解释它们的区别是什么以及我应该在不同情况下使用哪一个.任何评论表示赞赏.
Gui*_*ler 22
任何支持核心first和rest功能的对象都是sequence.
许多对象满足此接口,并且每个Clojure集合都提供至少一种seq对象,用于使用该seq函数遍历其内容.
所以:
user> (seq [1 2 3])
(1 2 3)
Run Code Online (Sandbox Code Playgroud)
你可以从创建序列对象map太
user> (seq {:a 1 :b 2})
([:a 1] [:b 2])
Run Code Online (Sandbox Code Playgroud)
这就是为什么你可以使用filter,map,for等对maps sets等.
因此,您可以将许多类似集合的对象视为序列.
这也是为什么许多序列处理函数,如filter调用seq输入:
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects."
{:added "1.0"
:static true}
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
Run Code Online (Sandbox Code Playgroud)
如果你打电话 (filter pred 5)
Don't know how to create ISeq from: java.lang.Long
RT.java:505 clojure.lang.RT.seqFrom
RT.java:486 clojure.lang.RT.seq
core.clj:133 clojure.core/seq
core.clj:2523 clojure.core/filter[fn]
Run Code Online (Sandbox Code Playgroud)
您看到该seq调用是此对象的序列验证.
如果你想要更深入的话,大部分内容都在第5章的Joy中.
Ada*_*old 13
在Clojure中,为了勇敢和真实,作者以一种真正可以理解的方式对其进行了总结:
集合抽象与序列抽象密切相关.Clojure的所有核心数据结构 - 向量,映射,列表和集合 - 都参与了这两种抽象.
抽象的不同之处在于序列抽象是"约"对成员的单独操作,而集合抽象是"关于"整个数据结构.例如,集合函数
count,empty?并且every?不是关于任何单个元素; 他们是关于整体的.
我刚刚读完《The Joy of Clojure》的第 5 章 - “集合类型”,这有点令人困惑(即该书的下一个版本需要回顾)。在第 5 章第 86 页,有一个我不太满意的表格:
\n\n\n\n这是我的看法(经过一个月的反思后完全更新)。
\n\n它是一个“东西”,是其他东西的集合。
\n\n这是基于函数的coll?。
coll?可用于对此进行测试。coll?返回 true 的东西都是集合。 文档coll?字符串说:
\n\n\n如果 x 实现则返回 true
\nIPersistentCollection
事物是分为三个不同类的集合。不同阶级的事物永远不平等。
\n\n(map? foo)测试\n\n(sequential? (sorted-map :a 1);=> 错误(set? foo)\n\n设置测试(sequential? (sorted-set :a :b));=> 错误(sequential? foo)\n\n进行测试(sequential? (seq [1 2 3]));=> true(sequential? (lazy-seq (seq [1 2 3])));=> trueJava 互操作的内容不在此列:
\n\n(coll? (to-array [1 2 3]));=> 假(map? (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2)));=> 假它是一个“东西”,一个按照特定的、稳定的顺序保存其他东西的集合。
\n\n这是基于函数的sequential?。
sequential?可用于对此进行测试。sequential?返回 true 的内容都是顺序集合。文档sequential?字符串说:
\n\n\n如果 coll 实现 Sequential,则返回 true
\n
注意:“顺序”是形容词!在《The Joy of Clojure》中,形容词被用作名词,这真的非常非常令人困惑:
\n\n\n\n\n“Clojure 将每个集合数据类型分为三个逻辑类别或分区之一:顺序、映射和集合。”
\n
应该使用“顺序事物”或“顺序集合”(如上面所使用的),而不是“顺序”。另一方面,在数学中已经存在以下术语:“链”、“全序集”、“单序集”、“线性有序集”。“链条”听起来很棒,但没有人使用这个词。耻辱!
\n\n《Joy of Clojure》也有这样的说法:
\n\n\n\n\n当心基于类型的谓词!
\n\nClojure 包含一些谓词,其名称类似于刚刚定义的单词。尽管它们\xe2\x80\x99 不经常使用,但似乎值得一提的是,它们可能并不完全符合此处定义的含义。例如,每个对象的顺序是什么?returns\n true 是一个顺序集合,但对于某些也是顺序的集合返回 false [更好:“可以被视为顺序\n 集合”]。这是因为 Clojure 的未来版本可能会改进实现细节 [也许这已经完成了?]
\n
这更多的是一个概念而不是一个事物:一系列可能存在也可能不存在的值(因此排序)(即流)。如果说一个事物是一个序列,那么这个事物是否也一定是一个 Clojure 集合,甚至是一个顺序集合?我想是这样。
\n\n该顺序集合可能已被完全计算并且完全可用。或者它可能是一台根据需要生成值的“机器”(通过计算 - 可能以“纯粹”方式 - 或通过查询外部“不纯”、“神谕”来源:键盘、数据库)
\n\n这是一个东西:可以被函数处理的东西\n first, rest, next, cons(可能还有其他?),即遵守协议 clojure.lang.ISeq的东西(这与Java中的“为接口提供实现”的概念大致相同) ,即系统已经注册了一对(事物,函数名称)的函数实现[我当然希望我得到了正确的结果......]
这是基于函数的seq?。
seq?可用于测试这一点seq?返回 true 的任何内容。文档字符串seq?:
\n\n\n如果 x 实现 ISeq,则返回 true
\n
文档字符串first:
\n\n\n返回集合中的第一项。对其参数调用 seq。\n 如果 coll 为 nil,则返回 nil。
\n
文档字符串rest:
\n\n\n返回第一个之后的可能为空的项目序列。在其参数上调用 seq\n。
\n
文档字符串next:
\n\n\n返回第一个之后的项目的序列。对其参数调用 seq。\n 如果没有更多项目,则返回 nil。
\n
您调用nextseq 来生成下一个元素和一个新的 seq。重复直到nil获得。
Clojure 的乐趣称其为“用于导航集合的简单 API”,并表示“seq 是实现 seq API 的任何对象”——如果“API”是“事物”(某种类型)的整体,则这是正确的以及对该事物起作用的功能。这取决于 API 概念的适当转变。
\n\n关于空 seq特殊情况的注释:
\n\n(def empty-seq (rest (seq [:x])))\n\n(type? empty-seq) ;=> clojure.lang.PersistentList$EmptyList\n\n(nil? empty-seq) ;=> false ... empty seq is not nil\n(some? empty-seq) ;=> true ("true if x is not nil, false otherwise.")\n\n(first empty-seq) ;=> nil ... first of empty seq is nil ("does not exist"); beware confusing this with a nil in a nonempty list!\n(next empty-seq) ;=> nil ... "next" of empty seq is nil\n(rest empty-seq) ;=> () ... "rest" of empty seq is the empty seq\n (type (rest empty-seq)) ;=> clojure.lang.PersistentList$EmptyList\n (seq? (rest empty-seq)) ;=> true\n (= (rest empty-seq) empty-seq) ;=> true\n\n(count empty-seq) ;=> 0\n(empty? empty-seq) ;=> true\nRun Code Online (Sandbox Code Playgroud)\n\nseq如果将该函数应用于seq有意义的事物(通常是顺序集合),您将得到一个表示/生成该集合的成员的 seq。
文档字符串说:
\n\n\n\n\n返回集合上的 seq。如果集合为空,则返回 nil。(seq nil) 返回 nil。seq 还适用于字符串、本机 Java\n 数组(引用类型)以及任何实现 Iterable 的对象。\n 请注意,seq 会缓存值,因此 seq 不应用于任何迭代器重复返回相同可变对象的 Iterable\n 。
\n
应用后seq,你可能会得到各种实际类的对象:
clojure.lang.Cons- 尝试(class (seq (map #(* % 2) \'( 1 2 3))))clojure.lang.PersistentList clojure.lang.APersistentMap$KeySeqclojure.lang.PersistentList$EmptyListclojure.lang.PersistentHashMap$NodeSeqclojure.lang.PersistentQueue$Seqclojure.lang.PersistentVector$ChunkedSeq如果应用seq到序列,返回的事物的实际类可能与传入的事物的实际类不同。它仍然是一个序列。
序列中的“元素”是什么取决于。例如,对于映射,它们是看起来像 2 元素的键值对vector(但它们的实际类并不是真正的向量)。
lazy-seq创建一个东西来延迟生成更多东西(一个暂停的机器,一个暂停的流,一个thunk)
\n\n文档字符串说:
\n\n\n\n\n获取返回 ISeq 或 nil 的表达式主体,并生成一个 Seqable 对象,该对象仅在第一次调用 seq 时调用主体,并缓存结果并在所有后续 seq 调用中返回它。另见——意识到了吗?”
\n
在 Clojure 宇宙中,我喜欢谈论“函数”和“事物”,但不喜欢谈论“对象”,因为“对象”是一个充满 Java 特性和其他缺点的术语。提到对象感觉就像是从底层 Java 宇宙中冒出来的碎片。
\n\n功能和事物有什么区别?
\n\n它是流体!有些东西是纯函数,有些东西是纯函数,有些介于两者之间(可以用作函数并具有事物的属性)
\n\n特别是,Clojure 允许将关键字(事物)视为函数(在映射中查找值)或将映射(事物)解释为函数或函数的简写(它采用一个键并返回与该键关联的值)的上下文。地图上的键)
\n\n显然,功能就是事物,因为它们是“一等公民””。
\n\n这也是有上下文的!在某些情况下,功能变成了事物,或者事物变成了功能。
\n\n有一些令人讨厌的对象提及......这些是从底层 Java 宇宙中冒出来的碎片。
\n\n| 归档时间: |
|
| 查看次数: |
5785 次 |
| 最近记录: |