【发布时间】:2017-01-01 11:00:11
【问题描述】:
我正在向Practical Common Lisp 学习 Common Lisp。它在第 24 章中有一个用于读取和写入二进制文件的辅助函数示例。这是一个示例:
(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 中编写一堆类似函数的最佳方法是什么?
【问题讨论】:
标签: common-lisp dry preprocessor