我想访问索引在列表中的数组。我们将此实用程序称为arefl
,其定义如下:
(arefl array '(x y z ...)) equals (aref array x y z ...)
我的目标是创建一些在任何大小的矩阵上运行的通用函数。
我没有用宏来实现这样的事情而只是aref
。我最接近的是:
(defmacro arefl (array is)
"Access array by a list of indices"
`(apply #'aref (cons ,array ,is)))
有效,实际上它也适用于(setf (arefl array is) value)
,但编译器(至少sbcl
)会发出警告,告诉我我正在重新定义setf
(我猜){ {1}}。警告是:
apply
-
有更好的方法吗?我正在寻找一个适用于; in: DEFUN (SETF AREFL**)
; (SETF (APPLY #'AREF ARRAY (REDUCE 'CONS ARGS :FROM-END T)) NEW-VALUE)
; --> LET* MULTIPLE-VALUE-BIND LET APPLY MULTIPLE-VALUE-CALL
; ==>
; #'(SETF AREF)
;
; caught STYLE-WARNING:
; defining as a SETF function a name that already has a SETF macro:
; (SETF AREF)
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
的实现,并且不需要调用setf
之类的其他函数,也不需要执行任何apply
答案 0 :(得分:2)
好的,define-setf-expander
对此有点矫枉过正。
(defun arefl (array list)
(apply #'aref array list))
(defun (setf arefl) (x array list)
(setf (apply #'aref array list) x))
请参阅“将表单应用为地点”:http://clhs.lisp.se/Body/05_abe.htm
答案 1 :(得分:2)
首先,虽然我认识到你说过
我正在寻找一个适用于
setf
的实现,并且不需要调用apply
之类的其他函数,也不需要执行任何cons
但是,你可以在这里使用apply 'aref
,你不需要cons
,因为只有{{} 1}}的最终参数需要是一个列表。这意味着以下所有内容都是等效的:
apply
最重要的是,如果您想避免调用(aref array 0 1)
(apply 'aref (list array 0 1))
(apply 'aref array (list 0 1))
(apply 'aref array 0 (list 1))
(apply 'aref array 0 1 '())
,则表示您可以执行
cons
您也可以使用(apply 'aref array indices)
(虽然您必须使用setf
,而不是#'array
):
'array
由于(setf (apply #'aref array indices) new-value)
适用于此处,您只需制作apply
和aref*
函数(与(setf aref*)
类似):
list*
其中(defun aref* (array &rest args)
(apply 'aref array (reduce 'cons args :from-end t)))
(defun (setf aref*) (new-value array &rest args)
(setf (apply #'aref array (reduce 'cons args :from-end t)) new-value))
用于支持spreadable argument list designators,(reduce 'cons args :from-end t)
使用apply
。使用此惯用法,您可以将完全相同类型的参数传递给您可以在(aref* ...)
中使用的(apply #'aref ...)
。这可能比你描述的用例复杂一点,但这意味着你不必专门描述aref*
所采用的各种参数,你可以简单地说(就像{{1的文档一样) ({1}}的args是一个可扩展的参数列表指示符,而apply
将aref*
应用于args。