1

I want to access arrays with the indices being in a list. Let's call this utility arefl, and it's defined as follows:

(arefl array '(x y z ...)) equals (aref array x y z ...) 

My goal is to create some generic functions that operate on matrices of any size.

I have failed to implement such a thing with macros and just aref. The closest thing that I have is:

(defmacro arefl (array is)
  "Access array by a list of indices"
  `(apply #'aref (cons ,array ,is)))

which works, and actually it also works with (setf (arefl array is) value) but the compiler, at least sbcl, throws a warning telling me that I'm redefining setf for (I guess) apply. The warning is:

; 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

--

Is there a better way? I'm looking for an implementation that works well with setf and does not need a call to another function like apply nor does do any cons

4

2 回答 2

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

于 2013-10-29T12:58:11.937 回答
2

首先,虽然我知道你说过

我正在寻找一种可以很好地使用setf并且不需要调用另一个函数的实现,也不需要调用apply任何函数cons

但是,您可以在这里简单地使用apply 'aref,并且不需要做任何consing,因为只有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*and(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))

(reduce 'cons args :from-end t)那些用于支持可扩展的参数列表指示符,这是什么apply用途。使用这个习语,您可以传递与in完全相同的参数类型。这可能比您描述的用例复杂一些,但这意味着您不必具体描述需要什么样的参数,您可以简单地说(就像 dos 的文档一样),即args 是可扩展的参数列表指示符,适用于 args。(aref* ...)(apply #'aref ...)aref*applyaref*aref*aref

于 2013-10-29T12:58:22.123 回答