1
votes

Here is a macro which I wrote to test a number for primality:

(defmacro primep (num)
  `(not (or ,@(loop for p in *primes* collecting `(= (mod ,num ,p) 0)))))

*primes* is a dynamic variable which contains a list of the primes generated so far (the context is a 'next prime generator' function). Here are the results of a few eval-ed statements:

(let ((*primes* (list 2 3)))
  (primep 6))
-> T

(let ((*primes* (list 2 3)))
  (macroexpand-1 '(primep 6))
-> (NOT (OR (= (MOD 6 2) 0) (= (MOD 6 3) 0)))
-> T

(NOT (OR (= (MOD 6 2) 0) (= (MOD 6 3) 0)))
-> NIL

What is going on?

1
You should use a function for this. Macros are for generating code. The problem here is that the LET binding for *PRIMES* happens at run-time, not during macroexpansion.jkiiski
@jkiiski How can I generate all those (= (mod ... statements using a function? I thought that was what macros are for (I've just started learning Common Lisp).shardulc says Reinstate Monica
You don't need to generate them. Use a loop just like in any other language.jkiiski
@jkiiski OK, thanks. I will try that. Can you add that (and maybe an example) as an answer so I can accept it?shardulc says Reinstate Monica

1 Answers

4
votes

You should use a function for this. Macros are for generating code. The problem here is that the LET binding for *PRIMES* happens at run-time, not during macroexpansion.

Your code as a function would look something like this.

(defparameter *primes* (list))

(defun primep (num)
  (not (loop for p in *primes* thereis (zerop (mod num p)))))

(let ((*primes* (list 2 3)))
  (primep 6))
;=> NIL

(let ((*primes* (list 2 3)))
  (primep 7))
;=> T