Как написать функцию multf на общем лиспе

Я ищу способ изменить значение свойства в списке свойств, умножив его на заданный коэффициент, аналогично использованию 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-expders и compiler-macros, но не знаю, применимы ли они здесь и как их использовать.


person Orm Finnendahl    schedule 06.07.2019    source источник


Ответы (1)


но это использует 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)
person Rainer Joswig    schedule 06.07.2019