SRFI 42中的热切理解可以有一个:while
子句在某些条件成立时运行生成器,例如:(list-ec (:while (:range i 10) (< (* i i) 50)) i)
返回列表(0 1 2 3 4 5 6 7)
(和停止迭代7,与if
不同,例如在(list-ec (:range i 10) (if (< (* i i) 50)) i)
中,它会继续运行,但不再生成值。)
在Racket中,我通常更喜欢使用原生的for
和for/list
,但它们似乎没有像内置的那样。在Racket :while
中模拟for
的最佳方法是什么?
答案 0 :(得分:7)
您可以使用#:break
循环中的for
子句执行类似的操作。例如,我认为这与您的示例相同:
(for/list ([i (in-range 0 10)]
#:break (> (* i i) 50))
i)
当#:break
条件成立时,这将停止迭代。您还可以使用#:when
来过滤迭代而不是停止。有关更多选项,请参阅for文档。
答案 1 :(得分:3)
我在文档中错过了它:答案是使用stop-before
function。你可以翻译像:
(list-ec (:while (:integers i) (< (* i i) 10))
(:while (:integers j) (< (* (+ i 1) j) 10))
(list i j))
到
(for*/list
([i (stop-before (in-naturals 0) (λ (i) (>= (* i i) 10)))]
[j (stop-before (in-naturals 0) (λ (j) (>= (* (+ i 1) j) 10)))])
(list i j))
请注意,我们需要加星标的版本for*/list
,因为list-ec
默认会生成嵌套循环。此外,正如Asumu Takikawa所指出的那样,Racket在其理解中有一个#:break
条款,但其工作方式不同:它不限制单个发生器,而是退出整个循环。