LOOP 宏

LOOP 宏的循环表达式被设计成类似英文语法,所以多数关键字有一些同义词,在不同的语境下可以更接近英语。作为 Common Lisp 独特特性之一的 LOOP,本身非常复杂,理解它的最好办法就是不断练习。

;;; from..to,递增循环 n 次,类似其他语言中的 for 循环:
(loop for i from 1 to 3 do (print i))
;; 输出:
;; 1
;; 2
;; 3
;; 以下示例,以 i 作为计数器,一直循环到 i=n 才结束,总共循环了 3 次,指定 below 关键字可以让它循环 n-1 次:
(loop for i from 1 below 3 do (print i))
;; 输出:
;; 1
;; 2

;;; by 关键字指定步长:
(loop for i from 1 to 10 by 2 do (print i))
;; 输出:
;; 1
;; 3
;; 5
;; 7
;; 9

;;; from..above,递减循环 n 次:
(loop for i from 10 above 0 do (print i))
;; 输出:
;; 10
;; 9
;; 8
;; 7
;; 6
;; 5
;; 4
;; 3
;; 2
;; 1

;;; in,遍历一个 list:
(loop for i in '(1 2 3 4 5) do (print i))
;; 输出:
;; 1
;; 2
;; 3
;; 4
;; 5

;;; 当然,如果是需要对每个元素做一些操作,推荐用和 map 相关的函数,如上的例子可用 mapcar 代替:
(mapcar #'print '(1 2 3 4 5))
;; 输出:
;; 1
;; 2
;; 3
;; 4
;; 5

;;; 遍历 association list(关联表):
;; for..in 也支持对关联表的遍历:
(loop for (k v) in '((:a 1) (:b 2) (:c 3)) do (format t "~S: ~S" k v)) ; => :A: 1:B: 2:C: 3
(loop for (k . v) in '((:a 1) (:b 2) (:c 3)) do (format t "~S: ~S" k v)) ; => :A: (1):B: (2):C: (3)
(loop for (k . v) in '((:a . 1) (:b . 2) (:c . 3)) do (format t "~S: ~S" k v)) ; => :A: 1:B: 2:C: 3

;;; on,cdr 方式递归列表:
;; 使用 on 关键字,每次都会返回列表的 cdr:
(loop for i on '(1 2 3 4 5) do (print i))
;; 输出:
;; (1 2 3 4 5)
;; (2 3 4 5)
;; (3 4 5)
;; (4 5)
;; (5)
;; across,迭代向量(vector):
(loop for i across #(1 2 3 4 5) do (print i))
;; 输出:
;; 1
;; 2
;; 3
;; 4
;; 5
;; 注意,字符串是由字符组成的向量,所以也可以用 across 遍历:
(loop for i across "hello" do (print i))
;; 输出:
;; #\h
;; #\e
;; #\l
;; #\l
;; #\o
;; hash-keys,按键迭代 hash 表:
(loop for k being the hash-keys in h do (print k)) ; h = (:a 1 :b 2 :c 3)
;; 输出:
;; :A
;; :B
;; :C
;; 可以取值:
(loop for k being the hash-keys in h using (hash-value v) do (print v))
;; 输出:
;; 1
;; 2
;; 3

;;; hash-values,按值迭代 hash 表:
(loop for v being the hash-values in h  do (print v))
;; 输出:
;; 1
;; 2
;; 3
;; 同样,也可以取键:
(loop for v being the hash-values in h  using (hash-key k) do (print k))
;; 输出:
;; :A
;; :B
;; :C

;;; with,指定循环的初始变量:
(loop with l = '(1 2 3) for i in l do (print i))
;; 输出:
;; 1
;; 2
;; 3
;; 请注意,“=”在这里是关键字,所以左右必须有空格,不能写成 l='(1 2 3)
;; 还可以指定子变量:
(loop for i from 1 to 3 for x = (* i i) do (print x))
;; 输出:
;; 1
;; 4
;; 9

;;; when,条件判断:
(loop for i from 1 to 10 when (evenp i) do (print i))
;; 输出:
;; 2
;; 4
;; 6
;; 8
;; 10

;;; while 和 until,循环终止条件:
;; while 直到满足条件后才执行 do 后面的表达式,并终止循环:
(loop for i from 1 to 10 while (oddp i) do (print i)) ; => 1
;; until 在没有满足条件之前会一直执行 do 后面的表达式:
(loop for i from 1 to 10 until (> i 5) do (print i))
;; 输出:
;; 1
;; 2
;; 3
;; 4
;; 5

;;; collect,循环构造列表,每次会把 collect 后面的表达式的指放入一个列表中:
(loop for i from 1 to 10 collect i)     ; => (1 2 3 4 5 6 7 8 9 10)

;;; append,连接列表:
(loop for i from 1 to 10 append (list i)) ; => (1 2 3 4 5 6 7 8 9 10)

;;; count,统计出循环过程中满足后面表达式的次数:
(loop for i from 1 to 10 count (oddp i)) ; => 5

;;; sum,汇总:
(loop for i from 1 to 10 sum i)         ; => 55

;;; maximize,求最大值:
(loop for i from 1 to 10 maximize i)    ; => 10
(loop for i from 1 to 10 maximize (* i 2)) ; => 20

;;; minimize,求最小值:
(loop for i from 1 to 10 minimize i)    ; => 1
(loop for i from 1 to 10 minimize (* i 2)) ; => 2