如何避免 Clojure 对我想要短路的惰性序列的分块行为? [英] How do I avoid Clojure's chunking behavior for lazy seqs that I want to short circuit?

查看:22
本文介绍了如何避免 Clojure 对我想要短路的惰性序列的分块行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很长的、懒惰的序列,我想减少它并懒惰地测试.只要两个顺序元素不是 =(或其他一些谓词)彼此,我就想停止使用列表,因为它的生成成本很高.是的,这听起来像 take-while,但请进一步阅读.

I have a long, lazy sequence that I want to reduce and test lazily. As soon as two sequential elements are not = (or some other predicate) to each other, I want to stop consuming the list, which is expensive to produce. Yes, this sounds like take-while, but read further.

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

I wanted to write something simple and elegant like this (pretending for a minute that every? works like reduce):

(every? = (range 100000000))

但这不会懒惰地工作,因此它挂在无限序列上.我发现这几乎如我所愿:

But that does not work lazily and so it hangs on infinite seqs. I discovered that this works almost as I wanted:

(apply = (range 100000000))

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

However, I noticed that sequence chunking was resulting in extra, unnecessary elements being created and tested. At least, this is what I think this is what happening in the following bit of code:

;; 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)))

我找到了一种解决方法,使用 take-whilecount 来检查采用的元素数量,但这相当麻烦.

I found a workaround using take-while, and count to check the number of elements taken, but that is rather cumbersome.

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

Should I politely suggest to Rich Hickey that he make some combination of reduce and every? short circuit properly, or am I missing some obvious way that already exists?

两位好心的人发布了避免在惰性序列上分块的解决方案,但是在执行 apply 时如何避免分块,这似乎在分块中消耗四人一组?

Two kind people posted solutions for avoiding chunking on the lazy sequences, but how do I avoid chunking when doing the apply, which seems to be consuming in chunked groups of four?

编辑 #2: 正如 Stuart Sierra 指出的那样,我独立发现,这实际上并不是分块.这只是适用于正常行为,所以我会称其为关闭并给他答案.对于感兴趣的人,我在单独的答案中包含了一个小函数来解决问题的减少部分.

EDIT #2: As Stuart Sierra notes and I discovered independently, this isn't actually chunking. It's just apply acting normally, so I'll call this closed and give him the answer. I included a small function in a separate answer to do the reduce'ing part of the problem, for those who are interested.

推荐答案

更正两次: 一种更简单的方法来解除惰性序列的分块:

CORRECTED TWICE: A simpler way to un-chunk a lazy sequence:

(defn unchunk [s]
  (when (seq s)
    (lazy-seq
      (cons (first s)
            (unchunk (next s))))))

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

First version omitted (when ... so it returned an infinite seq of nil's after the input sequence ended.

第二个版本使用 first 而不是 seq 所以它在 nil 上停止了.

Second version used first instead of seq so it stopped on nil.

RE:您的另一个问题,我如何在执行应用程序时避免分块,这似乎以四人一组的分块形式消耗":

这是由于 = 的定义,当给定参数序列时,它会强制第 4 个:

This is due to the definition of =, which, when given a sequence of arguments, forces the first 4:

(defn =
  ;; ... other arities ...
  ([x y & more]
   (if (= x y)
     (if (next more)
       (recur y (first more) (next more))
       (= y (first more)))
     false)))

这篇关于如何避免 Clojure 对我想要短路的惰性序列的分块行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆