2013-02-20 3 views
2

Как установить переменную для указания на ячейку списка?Ссылка на ячейку cons

Я пытаюсь написать макрос, чтобы умножить все значения в списке на значение. Это то, что я в настоящее время:

(defmacro scale (areas scale) 
    `(dotimes (n (list-length ,areas)) 
    (setf (nth n ,areas) (* (nth n ,areas) ,scale)))) 

Я беспокоюсь, что это не самый эффективный способ сделать что-то, как я смотрю на п-ю клетку дважды. Я предпочел бы установить переменную, указывающую на n-я ячейка, так что setf может изменить значение этой ячейки, а * может использовать значение этой ячейки в своих расчетах.

Еще лучше было бы использовать dolist и установить эту переменную в ссылку на ячейку. Это вообще возможно?

Пока я здесь, возможно ли получить следующую ячейку в списке, если у вас есть одна ячейка. Вроде как итератор, так что я могу сделать что-то вроде:

(let ((area (car areas)) 
    (loop while area do 
    (setf area (* area scale)) 
    (setf area (next area)))) 

Но я не знаю, как он будет проводить различие между установкой указателя или установив значение для ячейки.

я надеюсь, что имеет смысл :)

ответ

6

Главная проблема первого примера кода не то, что он находит nth клетки дважды, но это не использовать 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

+2

Приятное использование символа-макролета –

Смежные вопросы