在clojure中获取懒惰seq的第一个元素的惯用法

rob*_*oby 5 clojure lazy-sequences

处理seqI中的每个元素时,通常使用并休息.然而,这些将导致a lazy-seq通过调用seq论证而失去其"懒惰" .我的解决方案是在使用s 时使用(first (take 1 coll))(drop 1 coll)取而代之lazy-seq,虽然我认为drop 1很好,但我并不特别喜欢打电话firsttake获取第一个元素.

有没有比较惯用的方法呢?

Mic*_*zyk 10

文档字符串说first并且rest说这些函数调用seq它们的参数来传达这样的想法:seq当你传入一个seqable集合时你不必自称为自己,而seqable集合本身并不是一个seq,比如一个向量或集合.例如,

(first [1 2 3])
;= 1
Run Code Online (Sandbox Code Playgroud)

如果first没有呼吁seq它的论点就行不通; 你不得不说

(first (seq [1 2 3]))
Run Code Online (Sandbox Code Playgroud)

相反,这将是不方便的.

双方takedrop还呼吁seq对他们的论点,否则你不能打电话给他们上的载体和如上所述等.事实上,所有标准seq集合都是如此 - 那些不seq直接调用的集合构建在较低级别的组件上.

这绝不会损害懒惰的seqs的懒惰.由于first/ rest调用而发生的强制/实现是可能获得所请求结果的最小量.(多少取决于参数的类型;如果它实际上不是懒惰的,那么first调用中不会涉及额外的实现;如果它是部分惰性的 - 也就是说,分块 - 会有一些额外的实现(一次最多可计算32个初始元素);如果它完全是惰性的,则只计算第一个元素.)

显然first,当传递一个懒惰的seq时,必须强制实现它的第一个元素 - 这就是重点.rest实际上有点懒,因为它实际上并没有强制实现seq的"rest"部分(next与之形成鲜明对比,基本上相当于(seq (rest ...))).事实上,它确实强制第一个元素被实现,以便它可以立即跳过它是一个有意识的设计选择,它避免了懒惰的seq对象的不必要的分层并保持原始seq的头部; 你可以说(lazy-seq (rest xs))甚至推迟这个初步的实现,代价是坚持xs到实现懒惰的seq包装器.