使用doseq / for无限序列

时间:2016-03-08 15:29:03

标签: clojure clojurescript

在Clojure中,可以通过函数for的帮助迭代序列,或类似地使用doseq进行副作用,并将nil作为返回值:

(doseq [x (range 3)]
    (prn x))

; 0
; 1
; 2

对于序列无限的情况,有一种方法可以引入中断条件:

(doseq [x (range) :while (< x 3)]
    (prn x))

这将产生与上面相同的输出。

作为一种专业,当您使用多个序列时,会有一个非常有趣的行为。正如文档所称:&#34;集合以嵌套方式迭代,最快最快&#34;。

(doseq [x (range 3) y (range 3)]
    (prn x y))

; 0 0
; 0 1
; 0 2
; 1 0
; 1 1
; 1 2
; 2 0
; 2 1
; 2 2

但是,如果序列再次无限,会发生什么。当最后一个是无限的时,它运作得很好。这将像以前的例子一样起作用:

(doseq [x (range 3) y (range) :while (< y 3)]
    (prn x y))

如果第一个是无限的,则结果输出符合预期,但由于某些原因,在打印完最后一行之后循环不会停止。换句话说:repl继续工作。

(doseq [x (range) y (range 3) :while (< x 3)]
    (prn x y))

有人可以解释这种行为吗?

2 个答案:

答案 0 :(得分:13)

这没有意义:

(doseq [x (range) 
        y (range 3) 
        :while (< x 3)]
  (prn x y))

应该是:

(doseq [x (range) 
        :while (< x 3)
        y (range 3)]
  (prn x y))

...终止。

这样想:

(doseq [x (range)]
  (doseq [y (range 3) 
          :while (< x 3)]
    (prn x y)))

VS

(doseq [x (range)
        :while (< x 3)]
  (doseq [y (range 3)]
    (prn x y)))

在原始版本中,外环是无限的,内环中的:while没有区别。循环继续,它什么都不做。在固定版本中:while终止外部循环。

答案 1 :(得分:0)

鉴于muhuk的优秀解释,对于明确而不是过度压缩代码似乎是一个很好的论据。所以也许这样:

(doseq [x (range 3)]
  (doseq [y (range 3)]
    (prn x y)))

如果你可以控制输入序列,或者像这样:

(let [x-vals    (range)
      y-vals    (range) ]
  (doseq [x x-vals :while (< x 3)]
    (doseq [y y-vals :while (< y 3)]
      (prn x y))))

如果来自呼叫者的输入序列(例如x-valsy-vals)。