您的位置:首页 > 其它

《ANSI COMMON LISP》第二章 习题

2015-03-19 17:44 369 查看

作业部落简书 同步发布

不得不说,CSDN的页面表现没有上述两个个链接好看,请转看那两个中任何一个。

《ANSI COMMON LISP》读书笔记

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

(cons 'a '(b c))
(cons 'a (cons 'b (cons 'c '())))
(list 'a 'b 'c)


3. 使用
car
cdr
来定义一个函数,返回一个列表的第四个元素。

(defun fourth. (x)
    (car (cdr (cdr (cdr x)))))


4. 定义一个函数,接受两个实参,返回两者当中比较大的那个。

(defun max. (x y)
    (if (or (null x) (null y))
        nil
        (if (> x y) x y)))


5. 这些函数做两个什么?

(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
作为参数,返回
x
出现在列表
y
中的位置。

(b)中最后一句代码,当
y
中不存在
x
元素时,
z
nil
,
利用
and`的短路行为,不执行(+ z 1)。

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

(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的区别

apply接受一个函数和一个实参列表,并返回把传入参数应用于实参列表的结果。

apply 可以接受任意数量的实参,只要最后一个实参是列表即可。

函数funcall 做的是一样的事情,但不需要把实参包装成列表。

但apply和funcall是有区别的。


CL-USER> (apply #'list 1 nil)
(1)
CL-USER> (funcall #'list 1 nil)
(1 NIL)
CL-USER>


区别就在于参数使用方法是不同的。



对于
funcall
,在函数描述符之后的参数都是平等的,它们组合成一个列表让函数调用。

对于
apply
,最后一个参数必须为列表,并且是将列表中的每个元素与其他参数作为平等的参数对待,然后收集组合成一个列表让函数调用。



因此
apply
认为
nil
是一个空列表,内部无元素,与第一个参数组合是列表
(1)
list
调用。
funcall
认为
1
nil
是独立的两个参数,组合后交给
list
函数生成列表
(1 nil)


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

(defun haslist (x)
    (if (null x)
        nil
        (if (not (listp x))
            nil
            (if (listp (car x))
                t
                (haslist (cdr x))))))


8. 给出函数的迭代与递归版本:

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

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

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. 一位朋友想写一个函数,返回列表里所有非
nil
元素的和。他写了此函数的两个版本,但两个都不能工作。请解释每一个的错误在哪里,并给出正确的版本。

(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)))))))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: