附录 B:Lisp in Lisp

这个附录包含了 58 个最常用的 Common Lisp 操作符。因为如此多的 Lisp 是(或可以)用 Lisp 所写成,而由于 Lisp 程序(或可以)相当精简,这是一种方便解释语言的方式。

这个练习也证明了,概念上 Common Lisp 不像看起来那样庞大。许多 Common Lisp 操作符是有用的函式库;要写出所有其它的东西,你所需要的操作符相当少。在这个附录的这些定义只需要:

apply aref backquote block car cdr ceiling char= cons defmacro documentation eq error expt fdefinition function floor gensym get-setf-expansion if imagpart labels length multiple-value-bind nth-value quote realpart symbol-function tagbody type-of typep = + - / < >

这里给出的代码作为一种解释 Common Lisp 的方式,而不是实现它的方式。在实际的实现上,这些操作符可以更高效,也会做更多的错误检查。为了方便参找,这些操作符本身按字母顺序排列。如果你真的想要这样定义 Lisp,每个宏的定义需要在任何调用它们的代码之前。

  1. (defun -abs (n)
  2. (if (typep n 'complex)
  3. (sqrt (+ (expt (realpart n) 2) (expt (imagpart n) 2)))
  4. (if (< n 0) (- n) n)))
  1. (defun -adjoin (obj lst &rest args)
  2. (if (apply #'member obj lst args) lst (cons obj lst)))
  1. (defmacro -and (&rest args)
  2. (cond ((null args) t)
  3. ((cdr args) `(if ,(car args) (-and ,@(cdr args))))
  4. (t (car args))))
  1. (defun -append (&optional first &rest rest)
  2. (if (null rest)
  3. first
  4. (nconc (copy-list first) (apply #'-append rest))))
  1. (defun -atom (x) (not (consp x)))
  1. (defun -butlast (lst &optional (n 1))
  2. (nreverse (nthcdr n (reverse lst))))
  1. (defun -cadr (x) (car (cdr x)))
  1. (defmacro -case (arg &rest clauses)
  2. (let ((g (gensym)))
  3. `(let ((,g ,arg))
  4. (cond ,@(mapcar #'(lambda (cl)
  5. (let ((k (car cl)))
  6. `(,(cond ((member k '(t otherwise))
  7. t)
  8. ((consp k)
  9. `(member ,g ',k))
  10. (t `(eql ,g ',k)))
  11. (progn ,@(cdr cl)))))
  12. clauses)))))
  1. (defun -cddr (x) (cdr (cdr x)))
  1. (defun -complement (fn)
  2. #'(lambda (&rest args) (not (apply fn args))))
  1. (defmacro -cond (&rest args)
  2. (if (null args)
  3. nil
  4. (let ((clause (car args)))
  5. (if (cdr clause)
  6. `(if ,(car clause)
  7. (progn ,@(cdr clause))
  8. (-cond ,@(cdr args)))
  9. `(or ,(car clause)
  10. (-cond ,@(cdr args)))))))
  1. (defun -consp (x) (typep x 'cons))
  1. (defun -constantly (x) #'(lambda (&rest args) x))
  1. (defun -copy-list (lst)
  2. (labels ((cl (x)
  3. (if (atom x)
  4. x
  5. (cons (car x)
  6. (cl (cdr x))))))
  7. (cons (car lst)
  8. (cl (cdr lst)))))
  1. (defun -copy-tree (tr)
  2. (if (atom tr)
  3. tr
  4. (cons (-copy-tree (car tr))
  5. (-copy-tree (cdr tr)))))
  1. (defmacro -defun (name parms &rest body)
  2. (multiple-value-bind (dec doc bod) (analyze-body body)
  3. `(progn
  4. (setf (fdefinition ',name)
  5. #'(lambda ,parms
  6. ,@dec
  7. (block ,(if (atom name) name (second name))
  8. ,@bod))
  9. (documentation ',name 'function)
  10. ,doc)
  11. ',name)))
  1. (defun analyze-body (body &optional dec doc)
  2. (let ((expr (car body)))
  3. (cond ((and (consp expr) (eq (car expr) 'declare))
  4. (analyze-body (cdr body) (cons expr dec) doc))
  5. ((and (stringp expr) (not doc) (cdr body))
  6. (if dec
  7. (values dec expr (cdr body))
  8. (analyze-body (cdr body) dec expr)))
  9. (t (values dec doc body)))))

这个定义不完全正确,参见 let

  1. (defmacro -do (binds (test &rest result) &rest body)
  2. (let ((fn (gensym)))
  3. `(block nil
  4. (labels ((,fn ,(mapcar #'car binds)
  5. (cond (,test ,@result)
  6. (t (tagbody ,@body)
  7. (,fn ,@(mapcar #'third binds))))))
  8. (,fn ,@(mapcar #'second binds))))))
  1. (defmacro -dolist ((var lst &optional result) &rest body)
  2. (let ((g (gensym)))
  3. `(do ((,g ,lst (cdr ,g)))
  4. ((atom ,g) (let ((,var nil)) ,result))
  5. (let ((,var (car ,g)))
  6. ,@body))))
  1. (defun -eql (x y)
  2. (typecase x
  3. (character (and (typep y 'character) (char= x y)))
  4. (number (and (eq (type-of x) (type-of y))
  5. (= x y)))
  6. (t (eq x y))))
  1. (defun -evenp (x)
  2. (typecase x
  3. (integer (= 0 (mod x 2)))
  4. (t (error "non-integer argument"))))
  1. (defun -funcall (fn &rest args) (apply fn args))
  1. (defun -identity (x) x)

这个定义不完全正确:表达式 (let ((&key 1) (&optional 2))) 是合法的,但它产生的表达式不合法。

  1. (defmacro -let (parms &rest body)
  2. `((lambda ,(mapcar #'(lambda (x)
  3. (if (atom x) x (car x)))
  4. parms)
  5. ,@body)
  6. ,@(mapcar #'(lambda (x)
  7. (if (atom x) nil (cadr x)))
  8. parms)))
  1. (defun -list (&rest elts) (copy-list elts))
  1. (defun -listp (x) (or (consp x) (null x)))
  1. (defun -mapcan (fn &rest lsts)
  2. (apply #'nconc (apply #'mapcar fn lsts)))
  1. (defun -mapcar (fn &rest lsts)
  2. (cond ((member nil lsts) nil)
  3. ((null (cdr lsts))
  4. (let ((lst (car lsts)))
  5. (cons (funcall fn (car lst))
  6. (-mapcar fn (cdr lst)))))
  7. (t
  8. (cons (apply fn (-mapcar #'car lsts))
  9. (apply #'-mapcar fn
  10. (-mapcar #'cdr lsts))))))
  1. (defun -member (x lst &key test test-not key)
  2. (let ((fn (or test
  3. (if test-not
  4. (complement test-not))
  5. #'eql)))
  6. (member-if #'(lambda (y)
  7. (funcall fn x y))
  8. lst
  9. :key key)))
  1. (defun -member-if (fn lst &key (key #'identity))
  2. (cond ((atom lst) nil)
  3. ((funcall fn (funcall key (car lst))) lst)
  4. (t (-member-if fn (cdr lst) :key key))))
  1. (defun -mod (n m)
  2. (nth-value 1 (floor n m)))
  1. (defun -nconc (&optional lst &rest rest)
  2. (if rest
  3. (let ((rest-conc (apply #'-nconc rest)))
  4. (if (consp lst)
  5. (progn (setf (cdr (last lst)) rest-conc)
  6. lst)
  7. rest-conc))
  8. lst))
  1. (defun -not (x) (eq x nil))
  2. (defun -nreverse (seq)
  3. (labels ((nrl (lst)
  4. (let ((prev nil))
  5. (do ()
  6. ((null lst) prev)
  7. (psetf (cdr lst) prev
  8. prev lst
  9. lst (cdr lst)))))
  10. (nrv (vec)
  11. (let* ((len (length vec))
  12. (ilimit (truncate (/ len 2))))
  13. (do ((i 0 (1+ i))
  14. (j (1- len) (1- j)))
  15. ((>= i ilimit) vec)
  16. (rotatef (aref vec i) (aref vec j))))))
  17. (if (typep seq 'vector)
  18. (nrv seq)
  19. (nrl seq))))
  1. (defun -null (x) (eq x nil))
  1. (defmacro -or (&optional first &rest rest)
  2. (if (null rest)
  3. first
  4. (let ((g (gensym)))
  5. `(let ((,g ,first))
  6. (if ,g
  7. ,g
  8. (-or ,@rest))))))

这两个 Common Lisp 没有,但这里有几的定义会需要用到。

  1. (defun pair (lst)
  2. (if (null lst)
  3. nil
  4. (cons (cons (car lst) (cadr lst))
  5. (pair (cddr lst)))))
  6. (defun -pairlis (keys vals &optional alist)
  7. (unless (= (length keys) (length vals))
  8. (error "mismatched lengths"))
  9. (nconc (mapcar #'cons keys vals) alist))
  1. (defmacro -pop (place)
  2. (multiple-value-bind (vars forms var set access)
  3. (get-setf-expansion place)
  4. (let ((g (gensym)))
  5. `(let* (,@(mapcar #'list vars forms)
  6. (,g ,access)
  7. (,(car var) (cdr ,g)))
  8. (prog1 (car ,g)
  9. ,set)))))
  1. (defmacro -prog1 (arg1 &rest args)
  2. (let ((g (gensym)))
  3. `(let ((,g ,arg1))
  4. ,@args
  5. ,g)))
  1. (defmacro -prog2 (arg1 arg2 &rest args)
  2. (let ((g (gensym)))
  3. `(let ((,g (progn ,arg1 ,arg2)))
  4. ,@args
  5. ,g)))
  1. (defmacro -progn (&rest args) `(let nil ,@args))
  1. (defmacro -psetf (&rest args)
  2. (unless (evenp (length args))
  3. (error "odd number of arguments"))
  4. (let* ((pairs (pair args))
  5. (syms (mapcar #'(lambda (x) (gensym))
  6. pairs)))
  7. `(let ,(mapcar #'list
  8. syms
  9. (mapcar #'cdr pairs))
  10. (setf ,@(mapcan #'list
  11. (mapcar #'car pairs)
  12. syms)))))
  1. (defmacro -push (obj place)
  2. (multiple-value-bind (vars forms var set access)
  3. (get-setf-expansion place)
  4. (let ((g (gensym)))
  5. `(let* ((,g ,obj)
  6. ,@(mapcar #'list vars forms)
  7. (,(car var) (cons ,g ,access)))
  8. ,set))))
  1. (defun -rem (n m)
  2. (nth-value 1 (truncate n m)))
  3. (defmacro -rotatef (&rest args)
  4. `(psetf ,@(mapcan #'list
  5. args
  6. (append (cdr args)
  7. (list (car args))))))
  1. (defun -second (x) (cadr x))
  2. (defmacro -setf (&rest args)
  3. (if (null args)
  4. nil
  5. `(setf2 ,@args)))
  1. (defmacro setf2 (place val &rest args)
  2. (multiple-value-bind (vars forms var set)
  3. (get-setf-expansion place)
  4. `(progn
  5. (let* (,@(mapcar #'list vars forms)
  6. (,(car var) ,val))
  7. ,set)
  8. ,@(if args `((setf2 ,@args)) nil))))
  1. (defun -signum (n)
  2. (if (zerop n) 0 (/ n (abs n))))
  1. (defun -stringp (x) (typep x 'string))
  1. (defun -tailp (x y)
  2. (or (eql x y)
  3. (and (consp y) (-tailp x (cdr y)))))
  1. (defun -third (x) (car (cdr (cdr x))))
  1. (defun -truncate (n &optional (d 1))
  2. (if (> n 0) (floor n d) (ceiling n d)))
  1. (defmacro -typecase (arg &rest clauses)
  2. (let ((g (gensym)))
  3. `(let ((,g ,arg))
  4. (cond ,@(mapcar #'(lambda (cl)
  5. `((typep ,g ',(car cl))
  6. (progn ,@(cdr cl))))
  7. clauses)))))
  1. (defmacro -unless (arg &rest body)
  2. `(if (not ,arg)
  3. (progn ,@body)))
  1. (defmacro -when (arg &rest body)
  2. `(if ,arg (progn ,@body)))
  1. (defun -1+ (x) (+ x 1))
  1. (defun -1- (x) (- x 1))
  1. (defun ->= (first &rest rest)
  2. (or (null rest)
  3. (and (or (> first (car rest)) (= first (car rest)))
  4. (apply #'->= rest))))