2013-02-20 30 views
2

如何设置变量以指向列表单元格?引用cons单元格

我正试图写一个宏来将列表中的所有值乘以一个值。这是我目前有:

(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)))) 

但我不知道它将如何设定指针或设置引用单元格的值进行区分。

我希望我是有道理的:)

回答

6

第一个代码示例的主要问题不在于它找到nth细胞 的两倍,但它确实使用nth可言。而不是获取单元格,获取下一个单元格,它是以前的单元格的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) 
+0

谢谢,我知道必须有办法获得下一个细胞。它没有点击它会成为单元格的“cdr”,但现在它变得非常有意义。 – Lerp 2013-02-21 10:10:06

+2

很好的使用symbol-macrolet – 2013-02-22 05:37:11