2

リストセルを指すように変数を設定するにはどうすればよいですか?

リスト内のすべての値に値を掛けるマクロを作成しようとしています。これは私が現在持っているものです:

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

n番目のセルを2回検索するので、これが最も効率的な方法ではないのではないかと心配しています。むしろ、n番目のセルを指すように変数を設定して、setfそのセルの値を変更し、そのセル*の値を計算に使用できるようにします。

さらに良いのはdolist、変数をセル参照に設定して使用することです。これは可能ですか?

私がここにいる間、セルが1つあるときに、リスト内の次のセルを取得することもできますか。イテレータのようなもので、次のようなことができます。

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

しかし、ポインタの設定と参照セルの値の設定をどのように区別するのかわかりません。

私は理にかなっていると思います:)

4

1 に答える 1

6

最初のコード例の主な問題は、nthセルを 2 回検出することではなく、セル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)
于 2013-02-20T19:23:31.870 に答える