如何设置变量以指向列表单元格?
我正在尝试编写一个宏来将列表中的所有值乘以一个值。这就是我目前所拥有的:
(defmacro scale (areas scale)
`(dotimes (n (list-length ,areas))
(setf (nth n ,areas) (* (nth n ,areas) ,scale))))
我担心这不是最有效的做事方式,因为我两次查看第n个细胞。我宁愿设置一个变量来指向第n个单元格,以便setf
可以修改该单元格的值,*
可以在其计算中使用该单元格的值。
更好的方法是使用dolist
并将变量设置为单元格引用。这有可能吗?
虽然我在这里,当你有一个单元格时,是否也可以在列表中获取下一个单元格。有点像迭代器,这样我可以做类似的事情:
(let ((area (car areas))
(loop while area do
(setf area (* area scale))
(setf area (next area))))
但我不知道它如何区分设置指针或设置引用单元格的值。
我希望我有道理:)
答案 0 :(得分:6)
第一个代码示例的主要问题不是找到nth
个单元格
两次,但它确实使用nth
。而不是获得nth
单元格,获取 next 单元格,该单元格是前一单元格的cdr
。
你不需要宏,所以让我们实现一个函数。那里 有多种方法可以在列表的每个缺点单元格上执行操作:
(defun scale (areas scale)
(do ((tail areas (cdr tail)))
((endp tail))
(setf (car tail)
(* (car tail) scale))))
(defun scale (areas scale)
(loop for tail on areas
do (setf (car tail)
(* (car tail) scale))))
(defun scale (areas scale)
(mapl (lambda (cell)
(setf (car cell)
(* (car cell) scale)))
areas))
有一种替代方法不涉及对car
的明确操作
每个细胞:
(defun scale (areas scale)
(map-into areas
(lambda (area)
(* area scale))
areas))
作为奖励,这里有一个dolist
- 像宏一样进行修改
正文中的“变量”传播到列表中:
(defmacro dolistref ((var list &optional result) &body body)
(let ((tail (gensym "TAIL"))
(head (gensym "HEAD")))
`(let ((,head ,list))
(symbol-macrolet ((,var (car ,tail)))
(do ((,tail ,head (cdr ,tail)))
((endp ,tail) ,result)
,@body)))))
;; usage example
(let ((a (list 1 2 3)))
(dolistref (item a a)
(incf item))) ;; => (2 3 4)