标准控制结构

一: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 隐式的包含在一个叫nil block 里面,

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

标准控制结构_第1张图片

三: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 
NIL
CL-USER> (dolist (x '(1 2 3))(print x)(if (evenp x)(return x)))
1 
2 
2
CL-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)
3551729050
CL-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))
Number
9
The 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))
3
A 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 values
CL-USER> (multiple-value-bind (x y z) (values 1 2 3)
	 		  (list x y z))
(1 2 3)
More variables than values
CL-USER> (multiple-value-bind (x y z) (values 1 2)
	   		(list x y z))
(1 2 NIL)
 Move values than variables
CL-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))   6
CL-USER> (multiple-value-list (values 'a 'b ' c))    (A B C)

你可能感兴趣的:(java,list,测试,lisp)