Ansi Common lisp 读书笔记 0
第一、二章
简单认识一下lisp#
根据 SICP 课程的提出的,认识一门语言需要问的三个问题
- 它的最基本单元是什么
- 它是怎么组合这些单元的
- 它抽象这些组合方法是什么 这本书我们都带着这些问题去看
表示方法#
首先,lisp 和传统的编程语言有一点很不一样。它模糊了数据和方法,统一使用 “s 表达式” 来表示。 例如函数,不再是声明一个名字和参数列表,之后实现它这种结构,而是像写一个表达式
(defun sum (n)
(let ((s 0))
(dotimes (i n s)
(incf s i))))
类似的,它的数据也是如此表示
'(1 2 3)
“'” 单引号的作用是一个语法糖,方便的表示后面的是数据,不是需要求值的表达式
lisp 还有一个符号的概念,这里没有介绍太清楚。只是先了解有这个东西,还有他也可以是被求值的,但是一般用的时候不需要求值,所以引用的时候也使用单引号来引用
'Symbol
结构#
lisp 是一个循环自解释的系统 它会把自己语言的高级抽象,通过自己的语言来展开,之后求值。如果要求值的表达式还是比较高级的抽象,会又重新进行展开,之后再求值。这样一直循环到可以用最基础的实现来求值,得出最后结果的过程
列表操作符#
- cons 链接 list 的第一个元素和后面的部分
- car 取 list 的第一个元素
- cdr 取 list 除了第一个元素后面的部分
谓词#
一般的,在 lisp 做条件判断的错作符称作谓词,一般为了可读性,自定义的谓词使用“p”结尾,例如
(listp '(a b c))
这个表达式求是判断(a b c)是否是list。值的结果是真,用 “t” 表示 上面的结果会返回
T
关于 not 和 null#
这里书里只介绍做相同的事,但是没有具体的解释。我们以后在看
函数#
函数的定义,我们使用 defun 操作符
关于递归#
这里只是说了lisp可以做递归,并举了些例子,并没有近一步说明。
先简单说一下,基本的递归是每次的执行的环境保存在栈中,之后到最内层的时候逐步的回归出栈。 递归在 lisp 的编译器中,会整体判断一个操作前后是否对某个值做入栈操作,来做尾递归的优化。
打印函数#
common lisp 使用format函数打印
占位符是 ~A,对应最后面参数列表的每个参数 ~% 表示换行
读入函数#
书中说 read 是一个解释器。
解释器#
解释器是对应的是求值器,他俩组合就是是前面说的循环求值的过程,lisp 的本质。 书里这里没有更多的解释,以后再看。
变量#
变量分为局部变量和全局变量
在sicp中,会叫做自由变量和限制变量 这个说法个人觉得一开始比较难理解,但是是说到本质的。 自由变量是可以替换的,替换前后程序的意义没有变换。限制变量是不可以的,如果换了,程序的意义就变了 如:
(setq c 1)
(setq d 2)
(defun f (x y)
(+ x y c))
如果将所有的x替换成m,y替换成n,意义完全没有变换 而要是把c换成d,程序的意义就变了
赋值#
对于复制,在函数试编程里,复制是破坏无状态的开始,让事情变得更的复杂。但是复制也解决一些问题必要的工具。 在其他 lisp 实现中(scheme)有复值的操作会以感叹号结尾来提示此操作会引入状态改变。
common lisp 中使用setf 操作符来负值
迭代#
在计算机更接近机器语言的层面,循环是跳转。在其他语言中是迭代的关键字来表示,lisp中是用递归,只是表现形式的不同 common lisp 中有定义的宏来实现迭代
函数作为对象#
其他对象的引用使用quote “'",函数的引用使用sharp-quote “#'"。
引用#
前面提到过两次引用了,本质都是防止引用的对象被求值
apply#
apply 书中是说了它的作用是把函数何其参数传给它,等价于执行函数及参数
funcall#
类似于 apply,都是接受函数引用和不定个数的参数,效果也相同,只是最后一个参数funcall 可以不是 list,apply 最后一个参数必须是 list
lambda#
在 lisp 中,一切皆可 lambda,例如 lambda 可以是赋值
((lambda (x y)
do some thing
) 1 2)
相当于
(let ((x 1)
(y 2))
do some thing
)
他们的效果是一样的
类型#
在 lisp 中,变量没有类型,但是为了使用类型,可以显示的标注一个变量的类型,说中说后面会讨论。在 sicp 中,解决一个横向隔离问题时引入了“类型”,只是用cons 将一个符号和变量cons起来,在去这个变量的时候使用cdr,取变量类型的时候使用car
书中说lisp中数值才有类型,详细的在后面会讨论