访问整数位的函数的公共Lisp setf扩展

访问整数位的函数的公共Lisp setf扩展,lisp,common-lisp,Lisp,Common Lisp,我正在用Common Lisp编写一个程序,它需要为数组中的大量条目存储一组状态位(整个程序在Lisp中几乎都是fortran),并且状态位在数组中的fixnum中编码为位。这些状态位的访问器实际上将由宏定义,因此我不必关心如何分配这些位,但可能需要一个示例读取器函数 (defun deadp (e) (logbitp 0 e)) (在现实生活中,这将是内联的,并充斥着声明,以确保它的快速性,但我认为这些在这里并不重要。) 我需要这些东西成为函数,因为我希望能够映射它们,但也因为使用宏到内

我正在用Common Lisp编写一个程序,它需要为数组中的大量条目存储一组状态位(整个程序在Lisp中几乎都是fortran),并且状态位在数组中的fixnum中编码为位。这些状态位的访问器实际上将由宏定义,因此我不必关心如何分配这些位,但可能需要一个示例读取器函数

(defun deadp (e)
  (logbitp 0 e))
(在现实生活中,这将是内联的,并充斥着声明,以确保它的快速性,但我认为这些在这里并不重要。)

我需要这些东西成为函数,因为我希望能够映射它们,但也因为使用宏到内联函数让我感觉很糟糕

然后我会用它来做这样的事情:

(defconstant status-index 3)
...
(dotimes (i nentries)
  (unless (deadp (aref entries i status-index))
    ...))
(在现实生活中,
(aref条目i状态索引)
将是
(状态条目i)
,这反过来需要一个
setf
方法,但我认为这很容易。)

当然,还有其他类似的单位标志,它们将有不同的位与之关联

所以,现在我想能够做到这一点:

(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(aref…)
,而是编写
(deadp people…
,其中
people
是人的数组。这很好,并且很容易看到如何使
setf
能够,除非我还想说
(deadp status)
,其中
status
只是一个fixnum。但是也许有更好的方法。

根据GET-SETF-EXPLANCE的SBCL文档,SETF扩展器必须: “返回SETF机器所需的五个值:临时 变量,用于填充变量的值列表,临时变量列表 用于新值、设置功能和访问功能。“ 设置函数和访问函数实际上只是在该位置设置和访问值的形式,而不是函数对象

试试这个:

(define-setf-expander deadp (place)
  (let ((new (gensym)))
    (values nil nil (list new)
            `(progn (setf (ldb (byte 1 0) ,place) (if ,new 1 0))
                    ,new)
            `(deadp ,place))))
样本扩展:

(let ((status 1))
  (setf (deadp status) t))
->
(let ((status 1))
  (LET* ((#:G605 T))
    (SETF (LDB (BYTE 1 0) STATUS)
            (IF #:G605
                1
                0))
    #:G605))

我想就是这样。我仍然不确定我是否理解(事实上我肯定我不理解!)
正确定义setf expander
,但这似乎是可行的。让我试着让我的代码使用它,这样我就可以正确地检查:如果是这样,我稍后会接受答案。谢谢。与其说是一个答案,不如说是一个“可能的替代方法”。使用位向量会给您带来多大的减速?还有多少内存?至少SBCL有效地实现了它们。@Vatine:事实上,我现在使用的是位向量!这是一个错误的地方来描述我试图做什么,但通过在fixnum数组中的元素中存储信息,我希望能够使用一个专门的数组,而不是一个通用数组或(我不这么做)两个数组。
(let ((status 1))
  (setf (deadp status) t))
->
(let ((status 1))
  (LET* ((#:G605 T))
    (SETF (LDB (BYTE 1 0) STATUS)
            (IF #:G605
                1
                0))
    #:G605))