Как написать функцию Multf в общем LISP - PullRequest
5 голосов
/ 06 июля 2019

Я ищу способ изменить значение свойства в списке свойств, умножив его на заданный коэффициент, аналогично использованию incf для добавления к значению.

С помощью incf я мог бы сказать:

(let ((seq '(:x 10 :y 3)))
 (incf (getf seq :y) 3)
 seq)

-> (:x 10 :y 5)

Используя макрос, я мог бы получить результат следующим образом, но дважды использовал getf:

(defmacro multf (place val)
  `(setf ,place (* ,place ,val)))

(let ((seq '(:x 10 :y 3)))
  (multf (getf seq :y) 2)
  seq)

-> (:x 10 :y 6)

КакМогу ли я сделать это, чтобы получить один и тот же результат, используя getf только один раз?

Возможно, есть пакеты с такой функциональностью, но я не смог найти его в сети.Любая помощь приветствуется!Это не домашняя работа, я просто пытаюсь оптимизировать свой код, и мне любопытно лучше понять язык.Я читал о setf-экспандерах и компиляторах-макросах, но я не знаю, применяются ли они здесь и как их использовать.

1 Ответ

6 голосов
/ 06 июля 2019

но это использует getf дважды

первая - это форма SETF, а вторая - получатель. Первый будет расширен SETF.

Краткое определение multf с использованием define-modify-macro может быть:

CL-USER 28 > (define-modify-macro multf (&optional (number 1)) *)
MULTF

CL-USER 29 > (let ((seq '(:x 10 :y 3)))
               (multf (getf seq :y) 2)
               seq)
(:X 10 :Y 6)

Полное расширение в LispWorks выглядит следующим образом:

(LET ((SEQ '(:X 10 :Y 3)))
  (LET* ((#:G1158 :Y))
    (LET* ()
      (LET ((#:G1157 (* (GETF SEQ #:G1158) 2)))
        (LET ((#:|Store-Var-1156| (SYSTEM::PRIMITIVE-PUTF SEQ #:G1158 #:G1157)))
          (SETQ SEQ #:|Store-Var-1156|)
          #:G1157))))
  SEQ)
...