我正在学习从Practical Common Lisp的Common Lisp。它具有读取和第24章写二进制文件下面是一个例子辅助函数的例子:如何在Common Lisp中编写类似的函数?
(defun read-u2 (in)
(+ (* (read-byte in) 256) (read-byte in)))
我可以写功能同样读其他类型的二进制数。但我认为这样做违反了DRY原则。此外,这些函数将会类似,所以我试图用宏来生成函数。
(defmacro make-read (n be)
`(defun ,(intern (format nil "READ~d~:[L~;B~]E" n be))
(&optional (stream *standard-input*))
(logior ,@(loop for i from 0 below n collect
`(ash (read-byte stream)
,(* 8 (if be (- n 1 i) i)))))))
(defmacro make-read-s (n be)
`(defun ,(intern (format nil "READ~d~:[L~;B~]E-S" n be))
(&optional (stream *standard-input*))
(let ((a (,(intern (format nil "READ~d~:[L~;B~]E" n be)) stream)))
(if (zerop (logand a ,(ash 1 (1- (* 8 n)))))
a
(logior a ,(ash -1 (* 8 n)))))))
(defmacro make-write (n be)
`(defun ,(intern (format nil "WRITE~d~:[L~;B~]E" n be))
(n &optional (stream *standard-output*))
(setf n (logand n ,(1- (ash 1 (* 8 n)))))
,@(loop for i from 0 below n collect
`(write-byte (ldb (byte 8 ,(* 8 (if be (- n 1 i) i))) n)
stream))))
(eval-when (:compile-toplevel :load-toplevel :execute)
(dolist (cat '("READ" "READ-S" "WRITE"))
(dolist (be '(nil t))
(dolist (n '(1 2 4 8))
(eval `(,(intern (format nil "MAKE-~a" cat)) ,n ,be))))))
它的工作原理。它生成读取和写入大小为1,2,4和8的无符号和有符号整数的函数。SLIME理解它。但我想知道是否有更好的方法。
在Common Lisp中编写一堆类似函数的最好方法是什么?
为什么不使用'&optional'?如果是为了提高效率,如果功能是内联的,它是否仍然适用? – nisekgao
@nisekgao:看我的编辑。 –