ACL阅读笔记
序
忽然间又发现这里了,两个月前看到时只有两章,现在已经四章了。翻译者还在辛勤地努力工作着,大致看看比pcl基础一些,看过pcl前十章回头再看这些东西,收获良多。
前言
- 有了宏、闭包以及运行期类别, Lisp 凌驾在面向对象程序设计之上。
- Lisp被设计成可扩展的
- 更高的抽象化与互动的环境
总之感觉Lisp不会像其它语言一样让你受限于工具,它是无所不能的......(勿喷,个人理解)
欢迎来到Lisp
Summary
- Lisp 是一种交互式语言。如果你在顶层输入一个表达式, Lisp 会显示它的值。
- Lisp 程序由表达式组成。一个表达式可以是原子,或一个由操作符跟着零个或多个参数的列表。前序表示法意味着操作符可以有任意数目的参数。
- Common Lisp 函数调用的求值规则: 对参数从左至右求值,然后把它们的值传入由操作符表示的函数。 quote 操作符有自己的求值规则,它逐字不变地返回参数。
- 除了平常的资料类型, Lisp 有符号与列表。因为 Lisp 程序是用列表来表示的,很简单写出能编程的程序。
- 三个基本的列表函数是 cons ,它创建一个列表; car ,它返回列表的第一个元素; 和 cdr ,它返回第一个元素之后的所有东西。
- 在 Common Lisp 中, t 表示 真 ,而 nil 表示 假 。在逻辑的语意中,任何不为 nil 的东西都视为 真 。基本的条件式是 if 。 and 与 or 是相似的条件式。
- Lisp 主要由函数所组成。你可以用 defun 来定义新的函数。
- 一个调用自己的函数是递归的。一个递归函数应该要被视为过程,而不是机器。
- 括号不是问题,因为程序员藉由缩排来阅读与编写 Lisp 程序。
- 基本的 I/O 函数是 read ,它包含了一个完整的 Lisp 语法分析器,以及 format ,它基由模版来产生输出。
- 你可以用 let 来创造新的局域变量,用 defparameter 来创造全域变量。
- 赋值操作符是 setf 。它的第一个参数可以是一个表达式。
- 函数式编程,意味着避免产生副作用,是 Lisp 的主导思维。
- 基本的迭代操作符是 do 。
- 作为一般 Lisp 对象的函数。它们可以被当成参数传入,并可以用 lambda 表达式来表示。
- 在Lisp 中,数值有类型,而不是变量。
my extract
-
quote
或`的作用,符号和值,列表与函数 - Lisp程序可以写出Lisp代码(这点看过pcl单元测试那章印象深刻)
- 递归
- format与read(I/O)
- 当我们想要写没有副作用的程序,那么定义多个表达式的函数主体就没有意义了。最后一个表达式的值,会被当成函数的返回值,而之前表达式的值都被舍弃了。如果这些表达式没有副作用,你没有任何理由告诉lisp ,为什么要去对它们求值。
-
你可以透过
setf
赋值,偷偷地创造全域变量。但源文件 (source files)中指出,明确地使用 defparameter 会比较好。 - 递归和迭代
- #'(sharp quote升引号),作为对象的函数
习题答案个人版
;1.a 14 ;1.b (1 5) ;1.c 7 ;1.d (nil 3) ;2. (cons a (cons b (cons c nil))) ;3. (defun my-fourth (lst) (car (cdr (cdr (cdr lst))))) ;4. (defun my-max (x y) (if (> x y) x y)) ;5.a ;;检查列表中是否有nil ;5.b ;;返回第一个参数(元素)在第二个参数(列表)中的位置 ;6.a car ;6.b or ;6.c apply ;7 (defun contain-list (lst) (if (null lst) nil (or (listp (car lst)) (contain-list (cdr lst))))) ;8.a ;;Iteration (defun plotdot (num) (do ((i 1 (+ i 1))) ((> i num) 'done) (format t "."))) ;;Recursive (defun plotdot-r (num) (if (= num 0) 'done (progn (format t ".") (plotdot-r (- num 1))))) ;8.b ;;Iteration (defun a-times (lst) (let ((times 0)) (dolist (obj lst) (if (eql obj 'a) (setf times (+ times 1)))) times)) ;;Recursive (defun a-times-r (lst) (if (null lst) 0 (if (eql 'a (car lst)) (+ (a-times-r (cdr lst)) 1) (a-times-r (cdr lst))))) ;9.a (defun summit (lst) (apply #'+ (remove nil lst))) ;9.b (defun summit (lst) (if (null lst) 0 (let ((x (car lst))) (if (null x) (summit (cdr lst)) (+ x (summit (cdr lst)))))))
列表
Summary
- 一个 cons 是一个含两部分的数据结构。列表用链结在一起的 cons 组成。
- 判断式 equal 比 eql 来得不严谨。基本上,如果传入参数印出来的值一样时,返回真。
- 所有 Lisp 对象表现得像指针。你永远不需要显式操作指针。
- 你可以使用 copy-list 复制列表,并使用 append 来连接它们的元素。
- 游程编码是一个餐厅中使用的简单压缩演算法。
- Common Lisp 有由 car 与 cdr 定义的多种存取函数。
- 映成函数应用函数至逐项的元素,或逐项的列表尾端。
- 嵌套列表的操作有时被考虑为树的操作。
- 要判断一个递归函数是否正确,你只需要考虑是否包含了所有情况。
- 列表可以用集合表示。数个内置函数把列表当作集合。
- 关键字参数是选择性的,并不是由位置所识别,是用符号前面的特殊标签来识别。
- 列表是序列的子类型。 Common Lisp 有大量的序列函数。
- 一个不是正规列表的 cons 称之为点状列表。
- 用 cons 对象作为元素的列表,可以拿来表示对应关系。这样的列表称为关联列表(assoc-lists)。
- 自动内存管理拯救你处理内存配置的烦恼,但制造过多的垃圾会使程序变慢。
my extract
- cons 真正所做的事情是,把两个对象结合成一个有两部分的对象,称之为 Cons 对象。概念上来说,一个 cons 是一对指针; 第一个是car ,第二个是cdr。
- 因为所有不是 Cons 对象的东西就是一个原子 (atom),
- NIL 是一个原子,同时也是一个列表。
- 每一次你调用 cons 时, Lisp 会配置一块新的内存给两个指针
- Lisp 复制的是指针,而不是列表,故两个变量会有 eql 的值
- nth 与 nthcdr 都是零索引的(zero-indexed)
- copy-list复制的好像是指针,copy-tree是整个结构(参见PCL第十三章)
- double-recursive
- 因为集合中没有顺序的概念,这些函数不需要保留原本元素在列表被找到的顺序
- 发现cons两个元素会产生(元素 . 元素)的结果,这其实就是dotted list
Specialized Data Structure
Summary
my extract
- 用make-array创造数组,用setf与aref存取数组
- 用vector创造向量,用svref存取向量
changelog
- 2012年04月04日 星期三 11时37分21秒
- 2012年04月05日 星期四 20时33分53秒
- 2012年04月07日 星期六 22时44分56秒
- 2012年04月20日 星期五 15时18分00秒