处理seq
中的每个元素时,我通常使用first和rest。
但是,通过在参数上调用lazy-seq
,这些会导致seq
失去“懒惰”。我的解决方案是在使用(first (take 1 coll))
s时使用(drop 1 coll)
和lazy-seq
,虽然我认为drop 1
很好,但我并不特别喜欢致电first
和take
以获取第一个元素。
是否有更惯用的方式来做到这一点?
答案 0 :(得分:10)
first
和rest
的文档字符串表示这些函数在其参数上调用seq
来表达您在传递时不必自己调用seq
的想法在一个seqable集合中,它本身不是一个seq,比如一个向量或集合。例如,
(first [1 2 3])
;= 1
如果first
未在其参数上调用seq
,将无效;你不得不说
(first (seq [1 2 3]))
相反,这将是不方便的。
take
和drop
都会在其参数上调用seq
,否则您无法在向量等上调用它们,如上所述。事实上,所有标准seq集合都是如此 - 那些不直接调用seq
的集合构建在较低级别的组件上。
这绝不会损害懒惰的seqs的懒惰。由于first
/ rest
调用而发生的强制/实现是获得请求结果的最小量。 (多少取决于参数的类型;如果它实际上不是懒惰的,first
调用中没有额外的实现;如果它部分是懒惰的 - 那就是,chunked - 那里将是一些额外的实现(一次最多可以计算32个初始元素);如果它是完全惰性的,则只计算第一个元素。)
显然first
,当传递一个懒惰的seq时,必须强制实现它的第一个元素 - 这就是重点。 rest
实际上有点懒,因为它实际上并没有强制实现seq的“rest”部分(与next
形成对比,这基本等同于(seq (rest ...))
) 。事实上,它确实强制第一个元素被实现,以便它可以立即跳过它是一个有意识的设计选择,它避免了懒惰的seq对象的不必要的分层并保持原始seq的头部;你可以说像(lazy-seq (rest xs))
之类的东西,甚至推迟这个初步实现,代价是坚持xs
,直到实现了懒惰的seq包装器。