Common Lisp 内置了一个强大的 Loop 宏。它非常有用且强大,我经常使用它。
我也听说过一个非常相似的东西,叫做“Iterate”。它看起来与 Loop 非常相似,但更有 Lispy 的感觉。这两者有什么区别?除了简单的风格偏好之外,是否还有任何理由切换到其中任何一个?
iterate
独有的一些东西:
条款没有严格的顺序loop
要求所有
for
子句出现在循环体之前,例如在 while
之前。没关系iter
:(iter (for x in '(1 2 99)
(while (< x 10))
(for y = (print x))
(collect (list x y)))
累积子句可以嵌套
collect
、
appending
等可以出现在任何地方:(iter (for x in '(1 2 3))
(case x
(1 (collect :a))
(2 (collect :b))))
finding
;; Finding the longest list in a list of lists:
(iter (for lst in '((a) (b c d) (e f)))
(finding lst maximizing (length lst)))
=> (B C D)
;; The rough equivalent in LOOP:
(loop with max-lst = nil
with max-key = 0
for lst in '((a) (b c d) (e f))
for key = (length lst)
do
(when (> key max-key)
(setf max-lst lst
max-key key))
finally (return max-lst))
=> (B C D)
x^2 - 4x + 1
的最小值:
(iter (for x from -5 to 5 by 1/100)
(finding x minimizing (1+ (* x (- x 4)))))
2
©Common Lisp 食谱第 198 页
next-iteration
iter
还有
first-iteration-p
和 (if-first-time then else)
。https://web.archive.org/web/20170713081006/https://items.sjbach.com/211/comparing-loop-and-iterate
generate
和
next
。生成器是惰性的,当明确表示时它会转到下一个值。(iter (for i in '(1 2 3 4 5))
(generate c in-string "black")
(if (oddp i) (next c))
(format t "~a " c))
b b l l a
NIL
https://sites.google.com/site/sabraonthehill/loop-v-iterprevious
(iter (for el in '(a b c d e))
(for prev-el previous el)
(collect (list el prev-el)))
=> ((A NIL) (B A) (C B) (D C) (E D))
尽管可以使用
loop
的并行绑定
and
:(loop for el in '(a b c d e)
and prev-el = nil then el
collect (list el prev-el))
更多条款
in-string
LOOP 提供收集、查找和附加功能。 ITERATE 有这些,还有 adjoining
、
、unioning
和nunioning
。accumulating
(iter (for el in '(a b c a d b)) (adjoining el)) => (A B C D)
(
adjoin
是集合运算)
LOOP有求和、计数、最大化、最小化。 ITERATE 还包括multiplying
和
reducing
。减少是广义减少构建器:(iter (with dividend = 100)
(for divisor in '(10 5 2))
(reducing divisor by #'/ initial-value dividend))
=> 1
https://web.archive.org/web/20170713105315/https://items.sjbach.com/280/extending-the-iterate-macro
(defmacro dividing-by (num &keys (initial-value 0))
`(reducing ,num by #'/ initial-value ,initial-value))
(iter (for i in '(10 5 2))
(dividing-by i :initial-value 100))
=> 1
但还有更多。https://common-lisp.net/project/iterate/doc/Rolling-Your-Own.html#Rolling-Your-Ownhttps://web.archive.org/web/20170713105315/https://items.sjbach.com/280/extending-the-iterate-macro
在附录中,我们看到两个loop
扩展示例。但它们实际上并不可移植,代码充满了
#+(or allegro clisp-aloop cmu openmcl sbcl scl) (ansi-loop::add-loop-path …
,sb-loop::add-loop-path
等迭代中缺少的东西
and
,但是
不需要?. 我可能失踪了。
但这还不是全部,还有更多差异。
带有
finding
的
loop
示例让 loop
看起来太糟糕了。我通常会做某事:(let ((longest))
(loop for l in '((a) (b c d) (e f))
do (when (> (length l) (length longest))
(setf longest l))
finally (return longest)))
;; => (B C D)
在
do
子句中,您通常可以编写非常正常的 Common Lisp。 当某些变量在循环期间收集/记忆某些结果值时,用
let
和 setf
包装网络循环这些值非常有用。但我明白,generators
是一个杀手级功能。