1
votes

I feel as though I'm in the same ballpark as Basic Lisp Macro error but when I imagine how the code should look when expanded I don't see a problem and macroexpand isn't helping because it just doesn't want to output anything I can print; macroexpand just runs the code for me.

(setf my-array (make-array 4 :initial-element 3))
(print my-array)

(setf (aref my-array 2) 5)
(print my-array)

(defmacro set3To5 (arrnum)
    (print (arrayp arrnum))
    (print arrnum)
    (setf (aref arrnum 3) 5)
)
(set3To5 my-array)

Running this gives me the output

argument MY-ARRAY is not an array

but if 'arrnum' is replaced by 'my-array' then it should be fine?

To quote from the linked question

Now on macro expansion, the macro ADD-TEST is called with the parameter VAR getting the value G, a symbol.

Certainly my-array is a symbol and it is the symbol I wish to manipulate so why is there a problem?

2
"macroexpand isn't helping because it just doesn't want to output anything" - That's because your macro doesn't return any code. It just tries to print some stuff.melpomene
@melpomene isn't it supposed to return the code that's in the 'body' parameter of defmacro?StackUser20004
No, the body of a macro is normal code that runs when the macro is called, just like a function.melpomene
@melpomene That would indeed explain why it's not working. Thank you! You helped me figure it out. Our teacher pointed us to tutorialspoint.com and from the gigamonkeys book, oh, they actually did show it once and I missed it.StackUser20004

2 Answers

1
votes

Let’s write down what would happen if a lisp were to evaluate your file line by line:

(setf my-array (make-array 4 :initial-element 3))

At this point we have MY-ARRAY bound to #(3 3 3 3)

(print my-array)

Prints #(3 3 3 3)

(setf (aref my-array 2) 5)
(print my-array)

Modifies an element and prints #(3 3 5 3)

(defmacro set3To5 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

Now the macro SET3TO5 has been defined.

(set3To5 my-array)

The first step here (which we haven’t mentioned before, even though it was happening) is macroexpansion. The compiler knows that SET3TO5 is a macro so it calls the macro function with MY-ARRAY (the symbol) as arguments. Let’s look at what happens inside that macro:

(print (arrayp arrnum))

Well ARRNUM is the symbol MY-ARRAY so this prints NIL, although possibly not to the stream you expect.

(print arrnum)

This prints MY-ARRAY.

(setf (aref arrnum 3) 5)

Well ARRNUM is not an array so you have an error here.

So we have failed to evaluate this expression because expanding the macro has failed.

Here are some other things you could do:

(defun set1 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

(defun set2 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

(defmacro set3 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

And now evaluate:

CL-USER> (set1 my-array)
T
#(3 3 5 3)
5
CL-USER> my-array
#(3 3 5 5)
CL-USER> (set2 my-array)
(SETF (AREF #(3 3 5 5) 3) 5)
CL-USER> (set2 'foo)
(SETF (AREF FOO 3) 5)
CL-USER> (setf (aref my-array 3) 1)
1
CL-USER> (set3 my-array)
5
CL-USER> my-array
#(3 3 5 5)
-1
votes

Long story short, the code should look like this to leave you with an array of (3 3 5 5).

(defmacro set3To5 (arrnum)
    `(print (type-of ,arrnum))
    `(setf (aref ,arrnum 3) 5)
)

GNU Common Lisp, at least, cares a lot about the difference between ` and ' (those are backtick/backquote and quote/apostrophe characters). What does backtick mean in LISP? The comma operator undoes the quotation for an element in the list, allowing you to plug in parameters or local variables, do ",@" for splicing in a list.

Lisp macros execute the code within their bodies and the return result should be a form that can then be executed, that is macro expansion.

It seems to be they just decided on magic to define how the two backquoted lines are both turned into code because it seems like you would have to put them both within a list and backquote the entire list and then return that list, but it does look neater this way.