clojure - 在 clojure 中获取惰性序列的第一个元素的惯用方法

标签 clojure lazy-sequences

处理 seq 中的每个元素时,我通常使用 firstrest 。 然而,这些将导致 lazy-seq 通过在参数上调用 seq 来失去其“惰性”。我的解决方案是在使用 lazy-seq 时使用 (first (take 1 coll))(drop 1 coll) 代替它们s,虽然我认为 drop 1 很好,但我不太喜欢必须调用 firsttake 来获取第一个元素。

有更惯用的方法吗?

最佳答案

firstrest 的文档字符串表示这些函数在其参数上调用 seq 来传达您不必这样做的想法当传入一个本身不是 seq 的可序列集合(例如向量或集合)时,您自己调用 seq 。例如,

(first [1 2 3])
;= 1

如果 first 没有在其参数上调用 seq 则不起作用;你必须说

(first (seq [1 2 3]))

相反,这会很不方便。

takedrop 也会在它们的参数上调用 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/

相关文章:

list - 理解递归定义的列表(用 zipWith 表示的 fibs)

scheme - 通过高阶累积过程展平Scheme中的惰性列表的惰性列表

clojure - 将惰性行序列写入 ClojureClr 中的文件而不进行反射

string - 为什么以下 Clojure 未检测到回文?

clojure - Clojure 源中的父 eval(阅读器)函数?

list - 关联或更新 Clojure 列表和惰性序列

linq - .NET 4.0 中有序列运算符实现吗?

maven - 莱宁根:如何在project.clj中设置Maven groupId和打包属性

dictionary - 调用函数到序列的所有项目

haskell - Haskell 在惰性求值期间会丢弃中间结果吗?