如何避免Clojure的懒惰seqs分块的行为,我想短路?
-
25-09-2019 - |
题
我有一个长期的,懒惰序列我想减少和测试懒惰地。只要两个连续的元素不是=
(或其他一些谓词)给对方,我想停止食用名单,这是昂贵的生产。是的,这听起来像take-while
,但进一步阅读。
我想写的东西简洁大方像这样(假装一分钟即every?
就像reduce
):
(every? = (range 100000000))
但是,这并不懒洋洋,所以它挂在无限seqs工作。我发现这几乎工作,因为我想:
(apply = (range 100000000))
然而,我注意到序列的组块被导致额外的,不必要的元件被创建和测试。至少,这是我认为这是在下面的代码位发生了什么:
;; 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-while
一种变通方法,并且count
检查拍摄元件的数量,但是这是相当麻烦的。
我应该礼貌地建议丰富希基说,他让reduce
和every?
短路的某种组合得当,还是我失去了一些明显的方式,已经存在?
编辑:两个善良的人张贴避免分块就懒序列解决方案,但如何避免做apply
,这似乎是在四个分块组被消耗时,分块
修改#2:强>如司徒塞拉利昂笔记和我发现独立地,这是不实际分块。这只是一般适用演技,所以我会打电话给这个封闭的,并给他答案。我包含在单独回答一个小功能做的问题reduce'ing部分,对于那些有兴趣谁。
解决方案
<强> TWICE CORRECTED:以未块更简单的方法懒序列:
(defn unchunk [s]
(when (seq s)
(lazy-seq
(cons (first s)
(unchunk (next s))))))
首先版本省略(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)))
其他提示
寻找在clojure.core在定义应用使得它明显,为什么它在四个一组的组块时apply
与无限序列使用。 Reduce
不短路,要么...所以我留下写我自己的解决方案:
(defn reducep
"Like reduce, but for use with a predicate. Short-circuits on first false."
([p coll]
(if-let [s (seq coll)]
(reducep p (first s) (next s))
(p)))
([p val coll]
(if-let [s (seq coll)]
(if-let [v (p val (first s))]
(recur p (first s) (next s))
false)
true)))
然后,使用司徒氏unchunk(一个额外的and
)
(defn unchunk [s]
(lazy-seq
(cons (first s)
(and (next s)
(unchunk (next s))))))
我得到:
(reducep = (map #(do (print %) %) (unchunk (range)))) ;; Prints 01, returns false
(reducep = (map #(do (print %) %) (repeat 20 1))) ;; returns true
(reducep = (map #(do (print %) %) (unchunk [0 0 2 4 5]))) ;; Returns false
(reducep = (map #(do (print %) %) (unchunk [2 2 2 2 2]))) ;; returns true
如果说作品对你来说,这国防部起来。
修改:司徒雷登的他编辑后unchunk修改后的版本可能是最好的一个在这个早期的岗位。
我发现这个职位,同时击中一个4clojure问题的时间限制 我发现的另一种方式,以避免在32块:
;; add another dummy sequence parameter to the map:
(apply = (map #(do (prn %2) %) (range) (range)))
地图的较高元数形式似乎不使用分块序列(Clojure的1.5)
您需要做的第二个参数的东西,所以幸福 明确有关,可能是更好的:
(apply = (map (fn [i _] (prn i) i) (range) (range)))
这是没有其他的解决方案,整洁,但可能是快速和肮脏的好 用途,如测试“是本缓慢的,因为分块的?”。
关于apply
,你可以使用partition
摆脱的序列对和他们=:
(every? #(apply = %) (partition 2 1
(map (fn [i _] (prn i) i) (range) (range))))
虽然reducep
看起来有用的。
PS。我不想给人的印象是分块的顺序是慢,它不是。 我的问题是,4clojure测试用例所说的“第一”在我的序列生成函数在 值的范围,所以分块装置I做32次的工作。 (PPS。我的代码仍然太慢)