私はCommon LispをPractical Common Lispから学んでいます。これは、第24章でバイナリファイルを読み書きするためのヘルパー関数の例を持ってここに1つの例を示します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:私の編集を参照してください。 –