ansi common lisp 第二章 笔记

 

发现仅仅看完一遍,然后做后面的练习题,很不顺。这就做做笔记,每一章小结一下。

2.1、求值规则:

由左至右对实参求值,将它们的数值传入函数,来返回整个表达式的值。
以下是当 (/ (- 7 1) (- 4 2)) 表达式被求值时的情形:
  1、Lisp 对 (- 7 1) 求值: 7 求值为 7 , 1 求值为 1 ,它们被传给函数 - ,返回 6 。
  2、Lisp 对 (- 4 2) 求值: 4 求值为 4 , 2 求值为 2 ,它们被传给函数 - ,返回 2 。
  3、数值 6 与 2 被传入函数 / ,返回 3 。
例外:quote操作符,’ 为其缩写
quote 操作符接受一个实参,并完封不动地返回它

> '(+ 3 5)
(+ 3 5)

 


2.2 数据类型:整数(integer)、字符串(string)、符号(symbol)、列表(lists)、特殊值

整数  如256,对自身求值

 >256
256

字符串  双引号包裹起来,如"myString",对自身求值

>“myString”
"myString"

符号  英文的单词,如symbol,(通常?)不对自身求值,需quote操作符来引用,值都为大写

>'symbol
SYMBOL

列表  由被括号包住的零个或多个元素,可以嵌套,需要quote操作符引用,否则会被当做函数调用

> '(the list (a b c) has 3 elements)
(THE LIST (A B C) HAS 3 ELEMENTS)

特殊值  如nil,t
t,逻辑真:任何非nil都为真
nil,表示空的列表,等同于(),也表示逻辑假
typep,函数 typep 接受一个对象和一个类型,然后判定对象是否为该类型,是的话就返回真:

> (typep 27 'integer)
T

2.3 库函数:list,cons,car,cdr,null,not,listp,numberp,eql,format,read,remove,function,apply,funcall


list:创建列表    (list &rest args)

> (list 'my (+ 2 1) "Sons")
(MY 3 "Sons")

 

cons:构造列表,如果传入的第二个实参是列表,则返回由两个实参所构成的新列表    (cons se1 se2)

> (cons 'a '(b c d))
(A B C D)

   如果第二个实参是空表,则构建一个新表。上面的list,不过就是把几个元素加到 nil 上的快捷方式:

> (cons 'a (cons 'b nil))
(A B)
> (list 'a 'b)
(A B)

 

car:返回列表的第一个元素    (car list)

> (car '(a b c))
A

 

cdr:返回列表第一个元素之后的所有元素    (cdr list)

> (car '(a b c))
(B C)

 

listp:判断之后的实参是否是列表    (listp object)

> (listp '(a b c))
T
> (listp 27)
NIL

 

numberp:判断之后的参数是否为数字    (numberp object)

> (numberp 256)
T

 

null:如果实参为空列表,则返回逻辑真t    (null object)

>(null nil)
t

 

not: 逻辑取反     (not object)

>(not nil)
t

 

eql:测试两个实参是否相等,返回逻辑真或逻辑假    (eql x y)

>(eql 'a 'b)
nil

 

format:接受两个或两个以上的实参,第一个实参决定输出要打印到哪里,第二个实参是字符串模版,而剩余的实参,通常是要插入到字符串模版,用打印表示法(printed representation)所表示的对象。
    (format destination control-string &rest format-arguments)

> (format t "~A plus ~A equals ~A. ~%" 2 3 (+ 2 3))
2 plus 3 equals 5.
NIL

    打印出来的nil为format函数的返回值。 t代表输出到默认的设备,~A由后面的参数填入,~%表示换行

 

read:标准输入函数。这里简单介绍。没有任何参数时,从默认设备读取。    (read &optional (stream *standard-input*) (sb-impl::eof-error-p t) e-of value recursive -p)

> (read)
'a 
'A

    read函数的功能很强大。后面章节应该会详细介绍。

 

remove:接受一个对象和一个列表,返回不含这个对象的新列表    (remove item sequence &rest args &key from-end (test #'eql) test-not (start 0) end count key)

> (setf lst '(c a r a t))
(C A R A T)
> (remove 'a lst)
(C R T)

    如下所示,remove并没有实际更改lst的内容。这也展示了所谓的函数式编程。

> lst
(C A R A T)

2.4 控制结构 if,do,progn,dolist,


if:通常接受三个实参:一个 test 表达式,一个 then 表达式和一个 else 表达式。若 test 表达式求值为逻辑真 ,则对 then 表达式求值,并返回这个值。若 test 表达式求值 为逻辑假 ,则对 else 表达式求值,   并返回这个值                  

   (if test then &optional else)

> (if (listp '(a b c))
(+ 1 2)
(+ 5 6))
3
> (if (listp 27)
(+ 1 2)
(+ 5 6))
11

  if 的最后一个实参是选择性的。如果忽略它的话,缺省值是 nil :

> (if (listp 27)
(+ 1 2))
NIL

  if是特殊的操作符,因为不会对每一个参数求值,即绕过了一般的求值规则。

 


do:迭代操作符。     (do varlist endlist &body body)
   varlsit形式为(variable initial update) 其中 variable 是一个符号, initial 和 update 是表达式。最初每个变量会被赋予 initial 表达式的值;每一次迭代时,会被赋予 update表达式的值。
   第二个传给 do 的实参可包含一个或多个表达式。第一个表达式用来测试迭代是否结束。接下来在列表中的表达式会依序被求值,直到迭代结束。而最后一个值会被当作 do的返回值来返回。例子如下:

(defun show-squares (start end)
  (do ((i start (+ i 1)))
    ((> i end) 'done)
    (format t "~A ~A~%" i (* i i))))

 

progn:progn 接受任意数量的表达式,依序求值,并返回最后一个表达式的值。    (progn &rest forms)

 

dolist:遍历列表的元素并处理    (dolist (var list &optional result) &body body)

(defun our-length (lst)
    (let ((len 0))
        (dolist (obj lst)
            (setf len (+ len 1)))
            len))    

 

function: 特殊操作符,返回函数名字所管理的对象,缩写为#'    (function thing)

> (function +)
#<Compiled-Function + 17BA4E>

 

apply:函数也可以作为实参,apply接受一个函数和实参列表,并返回把传入函数应用在实参列表的结果:    (apply function arg &rest arguments)

> (apply #'+ '(1 2 3))
6

 

funcall:函数 funcall 做的是一样的事情,但不需要把实参包装成列表。    (funcall function &rest arguments)

> (funcall #'+ 1 2 3)
6

2.5宏操作符: and,or,lambda


and:逻辑操作符,接受任意数量的实参,如果所有实参都为真,则返回最后一个实参的值    (and &rest forms)

>(and t (+ 1 2))
3

   如果其中一个参数为假,则其后的参数都不再被求值,返回nil

 

or:逻辑操作符,接受任意数量的实参,如果有实参都为真,则返回此实参的值,且其后的参数都不再被求值    (or &rest forms)
  

这两个操作符都绕过了一般的求值规则。只有宏操作符和特殊的操作符可以绕过一般的求值规则。

 

lambda:一个 lambda 表达式是一个列表,列表包含符号 lambda ,接著是形参列表,以及由零个或多个表达式所组成的函数体。    (lambda args &body body)
    一个 lambda 表达式可以作为函数名。和普通的函数名称一样, lambda 表达式也可以是函数调用的第一个元素,

> ((lambda (x) (+ x 100)) 1)
101

2.6 变量操作 let,defparameter,defconstant,boundp,setf


let:引入新的局部变量。一个 let 表达式有两个部分。第一个部分是一组创建新变量的指令,指令的形式为 (variable expression) 。每一个变量会被赋予相对应表达式的值。一组变量与数值之后,是一个有表达式  的函数体,表达式依序被求值。最后一个表达式的求值结果作为 let 的返回值。

  (let bindings &body body)

> (let ((x 1) (y 2))
(+ x y))
3

 

defparameter:定义全局变量,为了避免与局部变量重名,一般全局变量命名为*variable*的形式    (defparameter var val &optional doc)

> (defparameter *glob* 99)
*GLOB*

 

 

defconstant:定义全局常量    (defconstant name value &optional documentation)

>(defconstant limit (+ *glob* 1)) 
LIMIT

 

      若有变量与全局常量重名,会有error发生。

 

boundp:检查某些符号是否为全局变量或全局常量    (boundp symbol)

> (boundp '*glob*)
T

 

 

setf:给全局变量或者局部变量赋值

> (setf *glob* 98)
98
> (let ((n 10))
(setf n 2)
n)
2

 

   如果 setf 的第一个实参是符号(symbol),且符号不是某个局部变量的名字,则 setf 把这个符号设为全局变量:

> (setf x (list 'a 'b 'c))
(A B C)

 

   setf的使用非常灵活。传入 setf 的第一个实参,还可以是表达式或变量名。在这种情况下,第二个实参的值被插入至第一个实参所引用的位置:

> (setf (car x) 'n)
N
> x
(N B C)

 

   还可以给 setf 传入(偶数)个实参。如下所示:

(setf a 'b
    c 'd
    e 'f)

 

2.7 定义新函数:defun 

通常接受三个以上的实参:一个名字,一组用列表表示的实参,以及一个或多个组成函数体的表达式    (defun name args &body body)

> (defun our-third (x)
  (car (cdr (cdr x))))
OUR-THIRD

posted on 2014-04-26 15:24  no1yizhe  阅读(248)  评论(0)    收藏  举报

导航