AIRobot

AIRobot quick note


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

ANSI Common Lisp Chapter 2

发表于 2019-01-02 分类于 未分类
本文字数: 3.1k 阅读时长 ≈ 3 分钟

Chapter 2 总结 (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 里,是数值才有类型,而不是变量。

Chapter 2 习题 (Exercises)

  1. 描述下列表达式求值之后的结果:

(a) (+ (- 5 1) (+ 3 7))

答案:14

(b) (list 1 (+ 2 3))

答案:(1 5)

(c) (if (listp 1) (+ 1 2) (+ 3 4))

答案:7

(d) (list (and (listp 3) t) (+ 1 2))

答案:(NIL 3)

  1. 给出 3 种不同表示 (a b c) 的 cons 表达式 。

答案:

1
2
3
(cons 'a '(b c))
(cons 'a (cons 'b '(c)))
(cons 'a (cons 'b (cons 'c nil)))
  1. 使用 car 与 cdr 来定义一个函数,返回一个列表的第四个元素。

答案:

1
2
(defun get-forth(lst)
(car (cdr (cdr (cdr lst)))))
  1. 定义一个函数,接受两个实参,返回两者当中较大的那个。

答案:

1
2
3
4
(defun get-max(x y)
(if (< x y)
y
x))
  1. 这些函数做了什么?

(a)

1
2
3
4
(defun enigma (x)
(and (not (null x))
(or (null (car x))
(enigma (cdr x)))))

答案:判断 x 列表中是否有 nil 元素

(b)

1
2
3
4
5
6
7
(defun mystery (x y)
(if (null y)
nil
(if (eql (car y) x)
0
(let ((z (mystery x (cdr y))))
(and z (+ z 1))))))

答案:查找 x 在列表 y 中的下标,如果没有则为 nil

  1. 下列表达式, x 该是什么,才会得到相同的结果?

(a)

1
2
3
> (car (x (cdr ‘(a (b c) d))))

B

答案:car

(b)

1
2
3
> (x 13 (/ 1 0))`

13

答案:or

(c)

1
2
3
> (x #’list 1 nil)

(1)

答案:or ‘(1) 或 apply

  1. 只使用本章所介绍的操作符,定义一个函数,它接受一个列表作为实参,如果有一个元素是列表时,就返回真。

答案:

非递归版本

1
2
3
4
5
(defun has-child-list (lst)
(let ((x nil))
(dolist (obj lst)
(setf x (or x (listp obj))))
x))

递归版本

1
2
3
4
5
6
(defun has-child-list-re (lst)
(if (null lst)
nil
(if (listp (car lst))
t
(has-child-list-re (cdr lst)))))
  1. 给出函数的迭代与递归版本:

a. 接受一个正整数,并打印出数字数量的点。

答案:

非递归版本

1
2
3
4
(defun print-dots (n)
(do ((i 0 (+ i 1)))
((= i n ) 'done)
(format t ".")))

递归版本

1
2
3
4
5
6
(defun print-dots-re (n)
(if (= n 0)
'done
(progn
(format t ".")
(print-dots-re (- n 1)))))

b. 接受一个列表,并返回 a 在列表里所出现的次数。

答案:

非递归版本:

1
2
3
4
5
(defun print-a-times (lst)
(let ((flag 'a)(x 0))
(dolist (obj lst)
(setf x (+ x (if (eql obj flag) 1 0))))
x))

递归版本:

1
2
3
4
5
6
(defun print-a-times-re (lst)
(if (null lst)
0
(let ((flag 'a))
(+ (if (eql flag (car lst)) 1 0)
(print-a-times-re (cdr lst))))))
  1. 一位朋友想写一个函数,返回列表里所有非 nil 元素的和。他写了此函数的两个版本,但两个都不能工作。请解释每一个的错误在哪里,并给出正确的版本。

(a)

1
2
3
(defun summit (lst)
(remove nil lst)
(apply #'+ lst))

答案:因为 remove 并不会改变 lst 本身。正确的程序:

1
2
3
(defun summit (lst)
(let ((newlst (remove nil lst)))
(apply #'+ newlst)))

(b)

1
2
3
4
5
(defun summit (lst)
(let ((x (car lst)))
(if (null x)
(summit (cdr lst))
(+ x (summit (cdr lst))))))

答案:因为递归没有边界退出分支。正确的程序:

1
2
3
4
5
6
7
(defun summit (lst)
(if (null lst)
0
(let ((x (car lst)))
(if (null x)
(summit (cdr lst))
(+ x (summit (cdr lst)))))))
OpenMP实现并行化
2019 goal
  • 文章目录
  • 站点概览
AIRobot

AIRobot

AIRobot quick note
130 日志
15 分类
23 标签
GitHub E-Mail
Creative Commons
  1. 1. Chapter 2 总结 (Summary)
  2. 2. Chapter 2 习题 (Exercises)
0%
© 2023 AIRobot | 716k | 10:51