处理 seq
中的每个元素时,我通常使用 first和 rest 。
然而,这些将导致 lazy-seq 通过在参数上调用 seq 来失去其“惰性”。我的解决方案是在使用 lazy-seq
时使用 (first (take 1 coll))
和 (drop 1 coll)
代替它们s,虽然我认为 drop 1
很好,但我不太喜欢必须调用 first
和 take
来获取第一个元素。
有更惯用的方法吗?
最佳答案
first
和 rest
的文档字符串表示这些函数在其参数上调用 seq
来传达您不必这样做的想法当传入一个本身不是 seq 的可序列集合(例如向量或集合)时,您自己调用 seq 。例如,
(first [1 2 3])
;= 1
如果 first
没有在其参数上调用 seq
则不起作用;你必须说
(first (seq [1 2 3]))
相反,这会很不方便。
take
和 drop
也会在它们的参数上调用 seq
,否则你无法像上面解释的那样在向量等上调用它们。事实上,所有标准 seq 集合都是如此——那些不直接调用 seq 的集合是建立在调用 seq 的较低级别组件之上的。
这绝不会削弱惰性序列的惰性。由于 first
/rest
调用而发生的强制/实现是获得所请求结果的可能的最小量。 (多少取决于参数的类型;如果它实际上不是惰性的,则 first
调用中不涉及额外的实现;如果它是部分惰性的——也就是说,分块-- 会有一些额外的实现(一次最多计算 32 个初始元素);如果是完全惰性的,则只计算第一个元素。)
显然,当传递一个惰性序列时,first
必须强制实现其第一个元素——这就是重点。 rest
实际上有点懒,因为它实际上并不强制实现 seq 的“rest”部分(这与 next
形成鲜明对比,后者基本上相当于(seq (rest ...))
)。事实上,它确实强制实现第一个元素,以便它可以立即跳过它,这是一个有意识的设计选择,可以避免不必要的惰性 seq 对象分层并保留原始 seq 的头部;您可以说类似 (lazy-seq (rest xs))
来推迟这个初始实现,但代价是保留 xs
直到意识到惰性 seq 包装器是实现了。
关于clojure - 在 clojure 中获取惰性序列的第一个元素的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18070962/