我正在使用Common Lisp编写一个程序,需要为数组中大量的条目存储一些状态位(整个程序基本上是将Fortran翻译为Lisp),状态位被编码为固定数字中的位数,这些数字均存储在这个数组中。这些状态位的访问器实际上将由宏定义,所以我不必关心分配这些位,但一个示例读取函数可能如下:
(defun deadp (e)
(logbitp 0 e))
在现实生活中,这些内容会被内联并且充斥着声明,以尝试确保它的速度,但我认为这些在这里并不重要。
我需要将这些东西作为函数,因为我想能够对它们进行映射,而且使用宏来内联函数的方式让我感觉很糟糕。
然后我会像这样使用它:
(defconstant status-index 3)
...
(dotimes (i nentries)
(unless (deadp (aref entries i status-index))
...))
在现实生活中,(aref entries i status-index)
应该是(status entries i)
,接下来需要一个setf
方法,但我认为这很容易。
或者
(loop for i below nentries
counting (if (deadp entries i status-index) 1 0))
当然,还会有其他类似的单比特标志,它们将具有不同的相关位。
所以,现在我想能够这样做:
(dotimes (i nentries)
...
(when ...
(setf (deadp (aref entries i status-index) t)))
...)
应该转换为相应的代码等效形式
(dotimes (i nentries)
...
(when ...
(progn
(setf (ldb (byte 1 0) (aref entries i status-index)) 1)
t))
...)
还有这个:
(let ((status 0))
...
(when ...
(setf (deadp status) t))
...)
这应该转化为相应的代码:
(let ((status 0))
...
(when ...
(progn
(setf (ldb (byte 1 0) status) 1)
t))
...)
换句话说,我希望我的
deadp
函数是一个存取器,对于它的 setf
可以以一般的方式工作:(setf(deadp(cdr x))nil)
应该可以工作等等。这让我进入了一些我长期避免的CL定义
setf
扩展程序。很明显,仅定义一个(setf deadp)
函数是行不通的,因为数字是不可变的,而且我相当确定 defsetf
的功能不够强大,所以我需要 define-setf-expander
,但我不理解。有人能解释一下我需要怎么做吗?我认为特定的
deadp
函数并不重要,尽管我关心的所有函数都看起来像它的变体。
另一种答案是“那是一种蠢方法,相反做...”,我也接受这种答案。我考虑过编写代码将数组抽象化,所以我会写
(deadp people ...)
而不是(deadp aref ...)
,其中 people
是人员数组。这是可以的,而且很容易看出如何使其成为可 setf
的,但我还想能够说(deadp status)
,其中 status
只是一个fixnum。但也许有更好的方法。