ANSI Common Lisp 学习笔记 第二章

scinart posted @ 2013年4月26日 23:44 in Lisp , 1985 阅读

可以用org-mode来查看

* 第二章:欢迎来到 Lisp
** #'third
** #'null
** #'listp
** #'if

(if ()
    ()
    ())

** #'and (macro)
** #'or (macro)
** #'format

(format t "~A plus ~A equals ~A. ~%" 2 3 (+ 2 3))

注意到有两个东西被打印出来。第一行是 format 印出来的。第二行是调用 format 函数的返回值,就像平常顶层会打印出来的一样。通常像 format 这种函数不会直接在顶层调用,而是在程序内部里使用,所以返回值不会被看到。
format 的第一个实参 t ,表示输出被送到缺省的地方去。通常是顶层。第二个实参是一个用作输出模版的字串。在这字串里,每一个 ~A 表示了被填入的位置,而 ~% 表示一个换行。这些被填入的位置依序由后面的实参填入。
** #'read 当没有实参时,会读取缺省的位置,通常是顶层。下面这个函数,提示使用者输入,并返回任何输入的东西
** #'let

(let [( )
      ( )
      ( )]
  (body))

** #'let*
** #'numberp
** #'defparameter 全局变量在任何地方都可以存取,除了在定义了相同名字的区域变量的表达式里。为了避免这种情形发生,通常我们在给全局变量命名时,以星号作开始与结束。刚才我们创造的变量可以念作 “星​​-glob-星” (star-glob-star)。
** #'defconstant 我们不需要给常量一个独一无二的名字,因为如果有相同名字存在,就会有错误产生 (error)。
** #'boundp 如果你想要检查某些符号,是否为一个全局变量或常量,使用 boundp 函数
** #'setf

(setf  
       
        .     .
        .     .
        .     .
       )

可以用来给全局或局部变量赋值 如果 setf 的第一个实参是一个符号(symbol),且这个符号不是某个局部变量的名字,那么 setf 将设置这个符号为全局变量: > (setf x (list 'a 'b 'c))

(A B C)

也就是说,通过赋值,你可以隐式地创建全局变量。 不过,一般来说,还是使用 defparameter 明确地创建全局变量比较好。 > (setf (car x) 'n) N > x

(N B C)

** #'remove 函数 remove 接受一个对象和一个列表,返回不含这个对象的新列表 原来的表没有被改变

(remove 'a '(a d c a d))

** #'do (macro)

(defun show-squares (start end)
  (do ((i start (+ i 1)))
      ((> i end) 'done)
    (format t "~A, ~A~%" i (* i i))))
(show-squares 4 6)

(do ((  ))
    ((   ... ))
  
  
  )

** #'progn
** #'dolist

(dolist (object /as in/ list)
  (do sth about object))

(defun print-list (lst)
  (dolist (obj lst)
    (if (listp obj)
	(print-list obj)
      (format t "~A~%" obj))))
(print-list '(1 (7 2) 4 6))

** #'function apply funcall

(function *)
(apply #'* '(2 2))
(funcall #'+ 1 2 6)
(funcall #'(lambda (x) (* x x)) 2)

** typep

(typep 27 'integer)

** Exercise
*** 1 描述下列表达式求值之后的结果

(a)

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

(b)

(list 1 (+ 2 3))

(c)

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

(d)

(list (and (listp 3) t) (+ 1 2))
*** 2 给出 3 种不同表示 (abc) 的 cons 表达式

(cons 'a (cons 'b (cons 'c nil)))
(cons 'a (cons 'b '(c)))
(cons 'a '(b c))

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

(defun my-fourth (lst)
  (labels ((n-th (lst n);assert n > 0
		 (if (and (> n 0)
			  (not (null (cdr lst)))
			  (listp (cdr lst)))
		     (n-th (cdr lst) (- n 1))
		   (if (= n 0)
		       (car lst)
		     nil))))
    (n-th lst 3)))
(my-fourth (list '(1 2 3) '(1 3 5) '(4 5 6) '(4)))

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

(defun greater (a b &optional (test-func #'>))
  (if (funcall test-func a b)
      a
    b))
(greater 'a 'b #'(lambda (a b) nil))

*** 5 这些函数做了什么? (a)

(defun enigma (x)
      (and (not (null x))
           (or (null (car x));(nil . else . else)
               (enigma (cdr x));(sth . nil . esle))
	       )))

;; guess: a test of structure (* . nil . else)

(enigma '(1 nil 3))
(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))))))

;; find if y contains x and return position

(mystery 5 '(1 2 3 4 5 6 7))

*** 6 下列表达式, x 该是什么,才会得到相同的结果? (a) >

(car (x (cdr '(a (b c) d))))

B ?

(car (car (cdr '(a (b c) d))))

(b) >< pre class="brush: lisp">(x 13 (/ 1 0)) 13 ?

(or 13 (/ 1 0))

(c) >

(x #'list 1 nil)

(1) ?

(apply #'list 1 nil)

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

(defun contains-list-p (lst)
  (let ((result nil))
    (dolist (obj lst)
      (if (listp obj)
	  (setf result t)))
    result))
(contains-list-p '(1 (2 5 7) 3))

*** 8 给出函数的迭代与递归版本: a 接受一个正整数,并打印出数字数量的点。 b 接受一个列表,并返回 a 在列表里所出现的次数。

(defun eight-a-init (int)
  (if (< int 0)
      nil
    (do ((i int (- i 1)))
	((= i 0) nil)
      (format t "."))))
(defun eight-a-recursive (int)
  (if (<= int 0)
      nil
    (progn
      (format t ".")
      (eight-a-recursive (- int 1)))))

;(eight-a-init 1) ;(eight-a-recursive -1)
*** 9 一位朋友想写一个函数,返回列表里所有非 nil 元素的和。他写了此函数的两个版本,但两个都不能工作。请解释每一个的错误在哪里,并给出正确的版本。 (a)

(defun summit (lst)
      (remove nil lst)
      (apply #'+ lst))

;; remove 无副作用,应为

(defun summit (lst)
  (apply #'+ (remove nil lst)))

(b)

(defun summit (lst)
      (let ((x (car lst)))
        (if (null x)
            (summit (cdr lst))
            (+ x (summit (cdr lst))))))

;;明显是出口没留出来,应为 (b)

(defun summit (lst)
      (if (null lst)
	  0
          (let ((x (car lst)))
	    (if (null x)
		(summit (cdr lst))
                (+ x (summit (cdr lst)))))))


 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter