Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a multf function in common lisp

I'm looking for a way to modify a property value in a property list by multiplying it with a given factor similar to using incf for adding to a value.

With incf I could say:

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

-> (:x 10 :y 5)

Using a macro I could obtain the result in the following way, but this uses getf twice:

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

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

-> (:x 10 :y 6)

How would I do this so that I could obtain the same result using getf only once?

Maybe there are packages with this functionality, but I couldn't find it in the net. Any help is appreciated! This is no homework, I'm just trying to optimize my code and I'm curious to better understand the language. I read about setf-expanders and compiler-macros, but I don't know whether they apply here and how to make use of them.

like image 605
Orm Finnendahl Avatar asked Jul 06 '19 08:07

Orm Finnendahl


1 Answers

but this uses getf twice

the first is a SETF form and the second one is a getter. The first one will be expanded by SETF.

A short definition of multf using define-modify-macro might be:

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)

The full expansion in LispWorks looks like this:

(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)
like image 138
Rainer Joswig Avatar answered Nov 18 '22 02:11

Rainer Joswig