标准控制结构

来源:互联网 发布:mac book pro 编辑:程序博客网 时间:2024/06/05 08:35

一:Block

Common Lisp has three basic operators for creating blocks Of code: progn, block, and tagbody.

block

A block is like a progn with a name and an emergency exit At any point within the body, you can halt evaluation and return a value immediately by using return-from with the block's name,

1:The second argument to return-from is returned as the value of the block named by the first。 return-from后第二个参数会作为以第一个参数为名字的block的值。

CL-USER> (block head   (format t "Here we go.")    (return-from head 'idea)    (format t "We'll never see this."))Here we go.IDEA

2There is also a return macro, which returns its argument as the value of an enclosing block named nil

CL-USER> (block nil   (return 27))27
3: Common lisp有一些操作符比如接受很多body的话,他会把这些body隐式的包含在一个叫nilblock里面,

CL-USER> (dolist (x '(a b c d e))   (format t "~A " x)   (if (eql x 'c)       (return 'done)))A B C DONE

4:用defun定义的function,也会隐式的把body放入到跟他的function name一样的block里面。

CL-USER> (defun foo ()   (return-from foo 27))FOO

Outside of an explicit or implicit block, neither return-from nor return will work.

Tagbody

The third basic block construct is tagbody, within which you can use gotos. Atoms appearing in the body are interpreted as labels;Most iteration operators have an implicit tagbody, but Most programmers will never use tagbody explicitly.

CL-USER> (tagbody    (setf x 0)  top    (setf x (+ x 1))    (format t "~A " x)    (if (< x 10) (go top)))1 2 3 4 5 6 7 8 9 10 NIL
二:Condition

If /when/unless

下面这个代码基本上也就概述了if/progn的实现功能。因为then-formelse-form都必须为单一的lisp形式,progn可以顺序执行任何数量的形式并返回最后一个形式的值。

CL-USER> (when (oddp that)   (format t "Hmm, that's odd.")   (+ that 1))Is equivalent to:CL-USER> (if (oddp that)     (progn       (format t "Hmm, that's odd.")       (+ that 1)))CL-USER> (unless nil   (format t "~a " 'first)   (format t "~a " 'second))FIRST SECOND NIL
Cond

当遇到多分支的条件语句时

Cond allow multiple condition. (test-1 form),只要test为真就执行form,下面的不再执行。t为不得已的处理方式

CL-USER> (defun our-member (obj 1st)   (cond ((atom 1st) nil) ((eql (car 1st) obj) 1st) (t (our-member obj (cdr 1st)))))

Case: begins with an argument whose value will be compared against the keys in each clause

CL-USER> (defun month-length (mon)   (case mon     ((jan mar may jul aug oct dec) 31)     ((apr jun sept nov) 30)     (feb (if (leap-year) 29 28))     (otherwise "unknown month")))
AND ,OR NOT

Not 接受单一形参,并对真值求反

AND OR都支持“短路”特性

AND 只有有一个表达式为NIL,就返回NIL,到最后无NIL,返回最后一个表达式的值。

OR   只要一个子表达式值为非NIL,就返回当前值,否则就返回NIL


三:Iterator Operator

The basic iteration operator is do, Since do contains both an implicit block and an implicit tagbody, we now know that it's possible to use return, return-f rom, and go within the body of a do

DOLISTDOTIMES

列表循环和计数循环,这两个宏提供易用却不怎么通用的结构,对于其他无法满足的情形,仍需要在DO之上构建自定义的循环结构

The third expression within the initial list will be evaluate and return as the value of dolist /dotimes when iteration terminates, it defaults to nil.

(dolist   (var list-form) body-form*)  var依次从list中取出后继来执行循环体

(dotimes (var count-form) body-form*),var持有的整数从0逐增到比那个数小1

CL-USER> (dolist (x '(1 2 3))(print x))1 2 3 NILCL-USER> (dolist (x '(1 2 3))(print x)(if (evenp x)(return x)))1 2 2CL-USER> (dotimes (i 4)(print i))0 1 2 3 NIL

DO

(do (variable-definition*)

(end-test-form result-form*)

Statement*)

Variable-definition是含有三个元素的列表(var init-form step-form)

init-form 开始绑定到var, 在下一次循环开始之前step-form赋值给var。 如果step-form未给的话,var将保持不变。如果init-form未给,将绑定到NIL

当循环开始以后,循环变量都被赋予了新值后,即新一轮的循环开始end-test-form(终止判断条件)会被求值。

end-test-form为真时,result-form(结果形式)将被求值,

在迭代的每一步,所有的step-form将在分配任何值给变量之前被求值。意味着可以在step-form中引用其他任何循环变量(比如下面就是这一轮的用上一轮的结果)理解do循环的关键部分。为啥它能够循环执行,因为它里面还有一个判断条件(end-test-form),有一点类似java中的do while.而现在由于本身变量定义就有一定的逻辑(第三个参数给变量赋值),所以有的时候就不需要循环体之类的,并且有的时候会省略结果形式,

(= 10 n)是一个终止条件,cur end-test-form为真是才求值。并且因为先给参数赋予新值才会判断终止条件,所以当判断到n=10时,上一轮的next已经变为这一轮的cur.所以最后的结果cur返回了第11个斐波那契数。

CL-USER> (do ((n 0 (+ 1 n))       (cur 0 next)        (next 1 (+ cur next)))     ((= 10 n) cur))55上面就是斐波那契省略了结果形式,(print i)只是一个打酱油的,即statement,最后整个式子的值是NIL.CL-USER> (do ((i 0 (1+ i)))      ((>= i 4))   (print i))     0 1 2 3 NIL

以上有的时候容易造成一些混乱,关键记住6个括号是do循环必备的,

一对括号围住变量声明

一对围住终止测试和结果形式

一对围住整个表达式

(do (variable-definition*)

(end-test-form result-form*)

Statement*)

下面的例子是即使没有没有循环变量,仍需给个变量的空列表。实现的功能是,在当前时间小于一个全局变量的时候,保持循环,每分钟打印一个waiting.

CL-USER> (get-universal-time)3551729050CL-USER> (do ()     ((> (get-universal-time) *some-future-date*))  (format t "waiting ~%")     (sleep 60))
四:Context

Let allow us to establish new variables for use within the body, because entering a let is conceptually equivalent to doing a function call 

CL-USER> (let ((x 7)       (y 2))   (format t "Number")   (+ x y))Number9The preceding l e t expression is exactly equivalent to:CL-USER> ((lambda (x y)    (format t "Number")    (+ x y))  7  2)

由于我们给出了let的等价形式,那么下面这个问题就很显而易见了。

CL-USER> (let ((x 2)        (y (+ x 1)))    (+ x y));   undefined variable: X因为上式等价于 CL-USER> ((lambda (x y) (+ x y))    2 (+ x 1))

Here it's obvious that the (+ x 1) passed as an argument to the function cannot refer to the parameter x within the function.

如果你想用这个X的话,就调用Let*方法。

CL-USER> (let* ((x 1)(y (+ x 1)))   (+ x y))3A let* is functionally equivalent to a series of nested lets .CL-USER> (let ((x 1))      (let ((y (+ x 1)))        (+ x y)))
五:Multiple Values

The maximum number of return values is implementation-dependent, but it will be at least 19.

Multiple values allow a function that calculates several things to return them without having to build a structure to contain them all. For example, the built-in get-decoded time returns the current time in nine values: second,minute, hour, date, month, day, and two others.

Multiple values also make it possible to have lookup functions that can distinguish between finding nil and failing to find something.

The values function returns multiple valuesCL-USER> (multiple-value-bind (x y z) (values 1 2 3)   (list x y z))(1 2 3)More variables than valuesCL-USER> (multiple-value-bind (x y z) (values 1 2)   (list x y z))(1 2 NIL) Move values than variablesCL-USER> (multiple-value-bind (s m h) (get-decoded-time)   (format nil "~A:~A:~A" h m s))"19:17:13"

multiple-value-call pass on multiple values as the arguments to a second function

multiple-value-list  like multiple-value-call with #'list as the first argument

CL-USER> (multiple-value-call #' + (values 1 2 3))   6CL-USER> (multiple-value-list (values 'a 'b ' c))    (A B C)