如何避免Clojure对于我想要短路的懒惰seqs的分块行为?

iva*_*var 14 clojure chunking lazy-sequences

我有一个漫长而懒惰的序列,我想减少并懒惰地测试.一旦两个连续元素彼此不相同=(或某些其他谓词),我想停止使用生产成本高昂的列表.是的,这听起来像是take-while,但请进一步阅读.

我想写一些简单而优雅的东西(假装一分钟every?就像这样reduce):

(every? = (range 100000000))
Run Code Online (Sandbox Code Playgroud)

但这不是懒惰的工作,所以它挂在无限的seqs.我发现这几乎和我想要的一样:

(apply = (range 100000000))
Run Code Online (Sandbox Code Playgroud)

但是,我注意到序列分块导致创建和测试额外的,不必要的元素.至少,这就是我认为这是在下面的代码中发生的事情:

;; Displays chunking behavior in groups of four on my system and prints 1 2 3 4
(apply = (map #(do (println %) %) (iterate inc 1)))

;; This prints 0 to 31
(apply = (map #(do (println %) %) (range)))
Run Code Online (Sandbox Code Playgroud)

我找到了一种解决方法take-while,并count检查所采用的元素数量,但这很麻烦.

我应该礼貌地向Rich Hickey建议他正确地进行了一些组合reduceevery?短路,还是我错过了一些已经存在的明显方法?

编辑:两种人发布了避免在懒惰序列上进行分块的解决方案,但是如何避免在进行分块时使用分块apply,这似乎在四个分组中消耗?

编辑#2:正如Stuart Sierra所说,我独立发现,这实际上并不是分块.它只是正常应用,所以我会把它叫做关闭并给他答案.对于那些感兴趣的人,我在一个单独的答案中包含了一个小函数来完成问题的减少部分.

Stu*_*rra 20

正确的两次:一种解决懒惰序列的简单方法:

(defn unchunk [s]
  (when (seq s)
    (lazy-seq
      (cons (first s)
            (unchunk (next s))))))
Run Code Online (Sandbox Code Playgroud)

省略了第一个版本,(when ...因此在输入序列结束后它返回了无限的nil seq.

第二个版本使用first而不是seq因此它停止在零.

RE:你的另一个问题是,"我在申请时如何避免分块,这似乎是在四人组中消耗的":

这是由于定义=,当给定一系列参数时,强制前4:

(defn =
  ;; ... other arities ...
  ([x y & more]
   (if (= x y)
     (if (next more)
       (recur y (first more) (next more))
       (= y (first more)))
     false)))
Run Code Online (Sandbox Code Playgroud)