0
votes

I am a common-lisp novice. I am having some troubles with the following macro:

What I have:

Suppose I have a global variable *JAN2018* which is:

(:NAME "*JAN2018*" :MONTH "Jan" :YEAR 2018 :EXPENSES (:VALUE NIL :TAGS NIL))

If I run

(setf (getf *jan2018* :expenses) '(:value 23 :tags '("a" "b")))

I get for *jan2018*

(:NAME "*JAN2018*" :MONTH "Jan" :YEAR 2018 :EXPENSES
 (:VALUE 23 :TAGS '("a" "b")))

The problem:

Now I have the macro:

(defmacro test (sym)
  (setf `(getf ,sym :expenses) '(:value 23 :tags '("a" "b"))))

If I run

(test *jan2018*)

I get (using SBCL)

*The function (COMMON-LISP:SETF COMMON-LISP:LIST*) is undefined.
   [Condition of type UNDEFINED-FUNCTION]*

What I am trying to do is pass a symbol and update one of its fields. Why I am getting this error, and how can I proceed to update the list?

1
Did you mean `(setf (getf ,sym :expenses) '(:value 23 :tags '("a" "b")))?melpomene
Ha! I see what is going on. The back quote before getf makes the argument to setf a list. Yes, it seems I meant that.Makketronix

1 Answers

3
votes

Your immediate problem

To debug a macro, use macroexpand:

(macroexpand-1 '(test *jan2018*))

*** - FUNCTION: undefined function (SETF CONS)

This is because you are trying to execute (setf (list 'getf *jan2018* ...) ...) at macro expansion time.

I am afraid I cannot offer any specific suggestions because it is not clear what exactly you are trying to accomplish by the macro.

Your actual problem

You are using an incorrect facility. Use function instead of macro:

(defun test (sym)
  (setf (getf sym :expenses) '(:value 23 :tags '("a" "b"))))