《ANSI COMMON LISP》讀書筆記
2. 給出3中不同表示(a b c)
的cons表達(dá)式咙边。
(cons 'a '(b c))
(cons 'a (cons 'b (cons 'c '())))
(list 'a 'b 'c)
3. 使用car
與cdr
來定義一個函數(shù),返回一個列表的第四個元素椭员。
(defun fourth. (x)
(car (cdr (cdr (cdr x)))))
4. 定義一個函數(shù)侥猬,接受兩個實參,返回兩者當(dāng)中比較大的那個欧漱。
(defun max. (x y)
(if (or (null x) (null y))
nil
(if (> x y) x y)))
5. 這些函數(shù)做兩個什么?
(a)
(defun enigma (x)
(and (not (null x))
(or (null (car x))
(enigma (cdr x)))))
(b)
(defun mystery (x y)
(if (null y)
nil
(if (eql (car y) x)
0
(let ((z (mystery x (cdr y))))
(and z (+ z 1))))))
(a):判斷列表x不為空表葬燎,但是存在空表元素误甚,如此則返回t
,否則返回nil
谱净。
(b):接受原子x
和列表y
作為參數(shù)窑邦,返回x
出現(xiàn)在列表y
中的位置。
(b)中最后一句代碼壕探,當(dāng)
y
中不存在x
元素時冈钦,z
為nil
,利用
and`的短路行為,不執(zhí)行(+ z 1)李请。
6. 下列表達(dá)式瞧筛,x
該是什么才會得到相同的結(jié)果?
(a) > (car (x (cdr '(a (b c) d))))
B
(b) > (x 13 (/ 1 0))
13
(c) > (x #'list 1 nil)
(1)
(a): car
(b): or
(c): apply
apply與funcall的區(qū)別
apply接受一個函數(shù)和一個實參列表导盅,并返回把傳入?yún)?shù)應(yīng)用于實參列表的結(jié)果较幌。
apply 可以接受任意數(shù)量的實參,只要最后一個實參是列表即可白翻。
函數(shù)funcall 做的是一樣的事情乍炉,但不需要把實參包裝成列表。
但apply和funcall是有區(qū)別的滤馍。
CL-USER> (apply #'list 1 nil)
(1)
CL-USER> (funcall #'list 1 nil)
(1 NIL)
CL-USER>
**區(qū)別**就在于參數(shù)使用方法是不同的岛琼。
- 對于
funcall
,在函數(shù)描述符之后的參數(shù)都是平等的纪蜒,它們組合成一個列表讓函數(shù)調(diào)用衷恭。 - 對于
apply
,最后一個參數(shù)必須為列表纯续,并且是將列表中的每個元素與其他參數(shù)作為平等的參數(shù)對待随珠,然后收集組合成一個列表讓函數(shù)調(diào)用灭袁。
因此,
apply
認(rèn)為nil
是一個空列表窗看,內(nèi)部無元素茸歧,與第一個參數(shù)組合是列表(1)
給list
調(diào)用。funcall
認(rèn)為1
和nil
是獨立的兩個參數(shù)显沈,組合后交給list
函數(shù)生成列表(1 nil)
软瞎。
7. 只是用本章所介紹的操作符,定義一個函數(shù)拉讯,它接受一個列表作為實參涤浇,如果有一個元素是列表時,就返回真魔慷。
(defun haslist (x)
(if (null x)
nil
(if (not (listp x))
nil
(if (listp (car x))
t
(haslist (cdr x))))))
8. 給出函數(shù)的迭代與遞歸版本:
a. 接受一個正整數(shù)只锭,并打印出數(shù)字?jǐn)?shù)量的點。
b. 接受一個列表院尔,并返回a在列表里所出現(xiàn)的次數(shù)蜻展。
a迭代:
(defun print-asterisk (x)
(if (or (null x) (listp x))
nil
(do ((i 1 (+ i 1)))
((> i x) 'done)
(format t "*"))))
a遞歸:
(defun print-asterisk (x)
(if (or (null x) (listp x))
nil
(if (> x 0)
(progn
(format t "*")
(print-asterisk (- x 1)))
'done)))
b迭代:(這樣不完整,沒有辦法遍歷每個元素的元素)
(defun num-of-a (lst)
(if (or (null lst) (not (listp lst)))
nil
(let ((num 0))
(dolist (obj lst)
(if (eql 'a obj)
(setf num (+ num 1))))
num)))
b遞歸:(這才是真正的遞歸遍歷所有的分支)
(defun num-of-a (lst)
(if (or (null lst) (not (listp lst)))
0
(if (eql 'a (car lst))
(+ 1 (num-of-a (cdr lst)))
(if (listp (car lst))
(num-of-a (car lst))
(num-of-a (cdr lst))))))
CL-USER> (num-of-a '((a b (a c (a d))) e f))
3
CL-USER>
9. 一位朋友想寫一個函數(shù)邀摆,返回列表里所有非nil
元素的和纵顾。他寫了此函數(shù)的兩個版本,但兩個都不能工作栋盹。請解釋每一個的錯誤在哪里施逾,并給出正確的版本。
(a)
(defun summit (lst)
(remove nil lst)
(apply #'+ lst))
(b)
(defun summit (lst)
(let ((x (car lst)))
(if (null x)
(summit (cdr lst))
(+ x (summit (cdr lst))))))
(a): remove并不能真正將lst里面的nil
去掉贞盯,而是其返回值中去掉了nil
音念。
(defun summit (lst)
(let ((x nil))
(setf x (remove nil lst))
(apply #'+ x)))
(b): 沒有停止條件
(defun summit (lst)
(if (null lst)
0
(let ((x (car lst)))
(if (null x)
(summit (cdr lst))
(+ x (summit (cdr lst)))))))