通过连接集合创建一个惰性序列。
考虑以下功能:
(defn req []
(Thread/sleep 1000)
(repeat 4 (rand-int 10)))
由于函数最终将成为http请求,因此会添加睡眠,因此它应该模拟延迟。
示例输出:
(req)
;; (8 8 8 8)
(req)
;; (4 4 4 4)
我现在正在考虑一个函数,它通过后续req
结果的连接创建一个懒惰的序列构建。
(take 10 (f req))
;; (3 3 3 3 2 2 2 2 9 9)
这是一个实现:
(defn f [g]
(lazy-seq (concat (g) (f g))))
这是要走的路吗?我以某种方式猜测可能已经有了这个可用的抽象..我尝试了lazy-cat
,但这个宏似乎只适用于固定数量的给定序列。
事实证明这是一个有效的抽象:
(take 10 (apply concat (repeatedly req)))
然而,看起来像懒惰序列的分块会导致req
被调用的频率超过此处所需,如果它是一个http请求,这是不可接受的。
答案 0 :(得分:3)
懒惰序列元素的“不必要”实现正在发生,因为apply
needs to know传递了函数的参数数量。
快速浏览一下Clojure核心库,似乎它没有提供连接序列序列的功能,同时以你想要的方式处理懒惰(不会冗余地实现传递的懒惰序列的元素),所以,你需要自己实现它。
这是可能的解决方案:
(defn apply-concat [xs]
(lazy-seq
(when-let [s (seq xs)]
(concat (first s) (apply-concat (rest s))))))
然后:
user> (defn req []
(println "--> making request")
[1 2 3 4])
#'user/req
user> (dorun (take 4 (apply-concat (repeatedly req))))
--> making request
nil
user> (dorun (take 5 (apply-concat (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 8 (apply-concat (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 9 (apply-concat (repeatedly req))))
--> making request
--> making request
--> making request
nil
这种方法的唯一问题是破坏堆栈的危险,因为 apply-concat
可能无限递归。
更新
准确地说apply
实现了传递的延迟序列的(arity of passed function + 1)
元素:
user> (dorun (take 1 (apply (fn [& xs] xs) (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 1 (apply (fn [x & xs] xs) (repeatedly req))))
--> making request
--> making request
--> making request
nil
user> (dorun (take 1 (apply (fn [x y & xs] xs) (repeatedly req))))
--> making request
--> making request
--> making request
--> making request
nil
答案 1 :(得分:2)
怎么样
(take 14
(mapcat identity (repeatedly req)))
说明:
(defn req []
(print ".")
(repeat 4 (rand-int 10)))
(def x
(take 80 (mapcat identity (repeatedly req))))
; prints .... = 4x ; this is probably some repl eagerness
; to take 80 items, 20 realizatons (of 4 items) are requrend
(def y
(doall
(take 80 (mapcat identity (repeatedly req)))))
; prints ..................... = 21x
编辑:关于那4个早期实现:
我认为这是apply
,我们mapcat
使用了[^clojure.lang.IFn f a b c d & args]
。
它实现了最多4个args constraints = {
audio: false,
video: {
width: 400,
height: 300,
deviceId: deviceId ? {exact: deviceId} : undefined
}
};
给出了多个。{/ p>