ANSI Common Lisp
第一章 基础知识
- quote 作为一种引用,也就是什么也不做,它的另一种表达形式是’
- list 函数用来创建列表
- 空列表的两种表达形式,() nil
- cons 用来构造列表,可以将多个列表合并为一个列表
- car 和 cdr 是一对亲兄弟,car 用来取列表第一个元素,cdr 用来取除第一个的剩余元素
- third 可以取第三个元素
- t 代表逻辑真,与 nil 一样,都是对自身求值
- listp 用来判断实参是否为列表,真则为 T ,假则为 NIL
函数的返回值将会被解释成逻辑 真 或逻辑 假 时,则称此函数为谓词(predicate) 在 Common Lisp 里,谓词的名字通常以 p 结尾。
- null 和 not 用来判断实参是否为空
if 和 qunto 都是特殊操作符,不能用函数实现,因为实参被调用时永远会被求值,
而 if 只有最后两个实参其中一个会被求值。
- if 的最后一个实参是选择性的。如果忽略它的话,缺省值是 nil
- 逻辑操作符 and 和 or ,两者都接受任意数量实参。如果所有实参同为真,and 则对能求值部分求值,否则为 nil, or 只要碰到一个为 真 的实参,则停止之后实参求值。
- and 和 or 操作符其实是宏,宏和特殊操作符一样,可以绕过一般求值规则。
- 用 defun 来定义函数
- 符号是变量的名字,符号本身就是以对象的方式存在。这也是为什么符号,必须像列表一样被引用。 列表必须被引用,不然会被视为代码。符号必须要被引用,不然会被当作变量。
- member 测试某个东西是否为列表成员
- 谓词 eql 用来判断它的两个实参是否相等
- 输出函数 format 接受两个或两个以上的实参,第一个决定打印到哪儿,第二个是字符串模版,剩余是要插入到字符串模板的参数。
- format 第一个实参 t 表示输出到缺省位置,通常是顶层。字符串模板里 ~A 表示被填入的位置,~% 表示一个换行。
- 输入函数 read 当没有实参时,会读取缺省位置,通常是顶层。read 是一个完整的 Lisp 解析器。
- let 用来定义局部变量,由两部分组成,第一部分是一组创建新变量的指令,第二部分是一个表达式。
- numberp 用来检测是否为数字
- defparameter 用来创建全局变量,由符号和值两部分组成。为了避免与局部变量发生冲突,在命名时以星号作开始结束。
- defconstant 用来定义一个全局常量。
- boundp 函数用来判断某些符号是否是一个全局变量或常量。
- setf 操作符用来给全局或局部变量赋值。
- 如果 setf 的第一个实参是符号(symbol),且符号不是某个局部变量的名字,则 setf 把这个符号设为全局变量
- 你不仅可以给变量赋值。传入 setf 的第一个实参,还可以是表达式或变量名。
- 你可以给 setf 传入(偶数)个实参,等同于分别对其传参。
- 函数 remove 接受一个对象和一个列表,返回不含这个对象的新列表。这里注意:remove 不是从列表内移除对象,因为原来的列表并没有改变。
- 如果要真正移除列表内元素,可以和 setf 搭配,remove 后将数据重写会原列表。例如:(setf lst (remove 'a lst))
- do 宏是 Common Lisp 里最基本的迭代操作符。和 let 类似, do 可以创建变量,而第一个实参是一组变量的规格说明列表。
- progn 接受任意数量的表达式,依序求值,并返回最后一个表达式的值。
- dolist 用来遍历列表元素
- function 是一个特殊操作符,将函数名传给它可以返回相关联的对象,而且无需引用。
- 如同 quote 可以用 ’ 代替,function 也可以用 #‘ 代替,#‘ 称为升引号。
- apply 接受一个函数和实参列表,并返回把传入函数应用在实参列表的结果。可以接受任意多实参,只要左后一个实参时列表即可。
- funcall 和 apply 类似,但无需将实参包装成列表。
- lambda 不是操作符而是个符号
- 要直接引用一个函数,我们使用所谓的lambda 表达式
- lambda 表达式也可以是函数调用的第一个元素,例如: ((lambda (x) (+ x 100)) 1)
- 通过在 lambda 表达式前面贴上 #' ,我们得到对应的函数。(funcall #'(lambda (x) (+ x 100)) 1)
- lambda 还允许我们使用匿名函数
- 函数 typep 接受一个对象和一个类型,然后判定对象是否为该类型
- common lisp 的内置类型,对象总是不止属于某种类型。例如:数字21有 fixnum 、 integer 、 rational 、 real 、 number 、 atom 和 t 类型,t 为所有类型的基类。
第二章 列表
- cons 把两个对象结合成一个有两部分的对象,称之为 Cons 对象。概念上来讲,一个 Cons 是一对指针;第一个是 car ,第二个是 cdr 。
- 嵌套列表和平坦列表
- consp 用来判断是否是 Cons 对象
- 所有不是 Cons 对象的东西,就是一个原子(atom)
- 注意:nil 既是一个原子,也是一个列表
- eql 和 equal 注意区别,前者有点类似全等,有关指针或内存空间。
- Lisp 没有指针,因为从概念上来讲每个值都是一个指针。
- append 函数返回任何数目的列表串接。
- (load "compress.lisp") 通过这种方式载入程序,注意,有些实现里的扩展名可能为.lsp
- nth 函数可以找到列表特定位置的元素,它们是用 car 跟 cdr 定义的
- nthcdr 函数可以找到第 n 个cdr
- zerop 函数仅在参数为零时,才返回真
- last 函数返回列表的最后一个 Cons 对象
- caddr 函数,它是 cdr 的 cdr 的 car 的缩写(car of cdr of cdr)
- cadr 函数可能会有异常产生
- mapcar 接受一个函数以及一个或多个列表,并返回把函数应用至每个列表的元素的结果,直到有的列表没有元素为止
- maplist 也是接受一个函数以及一个或多个列表,然后将列表渐进的下一个 cdr 传入函数
- 其他还有 mapc 和 mapcan
- Cons 对象可以想成是二叉树,car 代表左子树,而 cdr 代表右子树。
- 操作数的函数通常有这种形式,car 和 cdr 同时做递归。这种函数被称为双重递归。
- 列表是表示小集合的好方法,列表中的每个元素都代表了一个集合的成员
- member 函数用来查找集合内的元素是否存在,存在则返回由寻找对象所开始的那部分
- 一般情况,member 使用 eql 来比较对象。通过关键字作匹配,一个关键字是一个前面有冒号的符号
- member 函数接受的关键字 :test 参数和 :key 参数
- member-if 判断式可以通过类似 oddp 函数,来判断奇偶,奇数则返回真
- adjoin 函数像是条件式的 cons。它接受一个对象及一个列表,如果对象还不是列表的成员,才构造对象至列表上
- 集合论中的并集(union)、交集(intersection) 以及差集(complement)的实现,是由函数 union, intersection, set-difference
- 因为集合中没有顺序的概念,所以返回的顺序可能不尽相同
- 序列可以认为是一系列有特定顺序的对象,在 Common Lisp 里,序列包括列表与向量。
- length 函数返回序列中元素的数目
- subseq 函数用来复制序列的一部分,第二个(必须)参数是第一个开始引用进来的元素位置,第三个(可选)参数是第一个不引用进来的元素位置
- reverse 函数返回顺序颠倒的序列
- sort 排序函数接受一个序列及一个比较参数的函数,它是破坏性的,如果不想原序列被改动,传入一个副本。
- 传入列表副本可以用 copy-list 函数
- 函数 every 和 some 接受一个判断式及一个或多个序列。当仅输入一个序列时,他们测试序列元素是否满足判断式,当多于一个序列时,序列元素应该相同。
- push 宏用于将元素放入列表前端
- pop 宏用于将列表第一个元素移除,并返回这个元素
- push 和 pop 都是由 setf 定义的,例如:(push obj lst) 等同于 (setf lst (cons obj lst))
- pushnew 宏是 push 的变种,使用了 adjoin 而不是 cons
- 点状列表,调用 list 所构造的列表,也可以称为正规列表,它可以是 NIL 或是 cdr 是正规列表的 Cons 对象
- 一个由 Cons 对象组成的列表称为关联列表(assoclistor alist)
- assoc 函数用来取出在关联列表中,与给定的键值有关联的 Cons 对。和 member 一样,接受关键字参数 :test 和 :key
- assoc-if 类似 member-if
第三章 特殊数据结构
- make-array 可以构造一个数组,第一个实参为一个指定数组维度的列表
- Common Lisp 的数组至少可以达到七个维度,每个维度至少可以容纳 1023 个元素
- 用 aref 取出数组内的元素,它是零索引的
- 替换数组的某个元素,可以使用 setf 与 aref
- 表示字面常量的数组,使用 #na 语法,其中 n 是数组的维度,例如:
#2a((b nil nil) (nil nil nil))
- 一维数组又称向量(vector) 可以通过调用 vector 来构造及向量
- 可以用 aref 来存取向量,但有一个更快的函数叫做 svref 专门用来存取向量。
Comments:
Email questions, comments, and corrections to hi@smartisan.dev.
Submissions may appear publicly on this website, unless requested otherwise in your email.