先来了解下IF表达式:
(if condition then-form [else-form])
(if (> 2 3) "yes" "no") -> "no"
(if (> 2 3) "yes") -> NIL
(if (> 3 2) "yes" "no") -> "yes"
但是稍显不足之处在于IF表达式中的then-form和else-form都是single Lisp form。所以如果想顺序执行某个分支中的所有语句,只能如下形式:
(if (spam-p current-message)
(progn
(file-in-spam-folder current-message)
(update-spam-database current-message)))
这里的PROGN操作符,可按序执行其内部的任意数目的表达式,并以最后一个表达式的值作为PROGN表达式的值返回。
在Common Lisp中提供了宏WHEN以简化上面的代码:
(when (spam-p current-message)
(file-in-spam-folder current-message)
(update-spam-database current-message))
WHEN的定义如下:
(defmacro when (condition &rest body)
`(if ,condition (progn ,@body)))
与WHEN相对应的一个宏UNLESS的定义如下:
(defmacro unless (condition &rest body)
`(if (not ,condition) (progn ,@body)))
在使用IF表达式编程时,可能有这样的情况:if a do x, else if b do y, else do z.
这时可以用COND宏来简化代码:
(cond
(test-1 form*)
(test-2 form*)
.
.
.
(test-N form*))
NOT是系统函数,但是它与AND和OR联系非常紧密。它是单参数函数,当参数为NIL时返回T,否则返回NIL。
AND宏按顺序对其所有子表达式进行求值,一旦某个子表达式为NIL则立即返回,后面的子表达式均不在求值。
OR宏也是按顺序对其所有子表达式进行求职,一旦某个子表达式为non-NIL则立即返回,后面的子表达式均不在求值。
(not nil) -> T
(not (= 1 1)) -> NIL
(and (= 1 2) (= 3 3)) -> NIL
(or (= 1 2) (= 3 3)) -> T
(dolist (var list-form)
body-form*)
如果要在loop中途退出循环,可以使用RETURN,如:
(dolist (x '(1 2 3)) (if (> x 2) return) (format t "~d " x)) ;输出为: 1 2
DOTIMES是一个计数循环控制宏:
(dotimes (var count-form)
body-form*)
其中count-form必须能被求值为整数。var的范围为:[0, count-form)。如:
(dotimes (i 10) (if (> i 3) (return i) (format t "~d " i)) ; 输出为:1 2 3,表达式的返回值为4
由于DOLIST和DOTIMES都只支持一个循环变量,有时不够灵活,可以使用DO宏以支持任意的循环变量,并获取完全的循环控制能力。
(do (variable-definition*)
(end-test-form result-form*)
statement*)
每个variable-definition引入的变量仅在循环内可见,单个变量定义的list包括三个元素:
(var init-form step-form)
当end-test-form所求得的值为true时,result-form会被求值,并且最后一个result form将会作为DO表达式的返回值。如:
(do ((i 0 (1+ i))) ; 输出为: 1 2 3 4
((>= i 4)) ; DO表达式的返回值为NIL
(format t "~d " i))
LOOP宏,以其简单和扩展性著称,简单是因为它没有绑定任何变量:
(loop
body-form*)
同样地,在LOOP表达式内部可以通过RETURN跳出循环。