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