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秒