1

My task is to calculate list of all the primes between a and b using macro do-primes and then print them using the custom code.

Say (do-primes (n 5 15) (fresh-line) (princ n)) should print following 4 lines:

  1. 5
  2. 7
  3. 11
  4. 13

Here is my code:

(defun is-prime (n &optional (d (- n 1))) (or (= d 1) (and (/= (rem n d) 0) (is-prime n (- d 1))))) (defun my-func (a b) (let (lst '()) (loop for i from a to b do (if (is-prime i) (push i lst) ) ) (reverse lst)) ) (defmacro do-primes ((var startv endv) &body body) `(my-func ,startv ,endv) `(,@body) ) (do-primes (n 5 15) (fresh-line) (princ n)) 

But, when I run the code I have this error:

EVAL: (FRESH-LINE) is not a function name; try using a symbol instead

Any ideas how to make this code work properly?

3 Answers 3

5

Remember: Macros transform code.

If you have code like

(do-primes (n 5 15) (fresh-line) (princ n)) 

The first question you should ask yourself is: what should the transformed code look like? The code which then will actually run.

Once you know how the target code should look like, you can write the translation.

Lisp has similar macros: dolist and dotimes. You can check their macro expansion. There are several approaches to implement above. One is to use a function and a closure for the body. Typically, in Lisp, though I would expect them to expand into some low-level code doing the loop iteration.

In Pseudo code notation a more high-level coding approach would be:

for n from n below/upto 15 when is-prime (n) do fresh-line () and princ (n) 

So the do-primes macro would need to expand into similar code - but Lisp code. Lots of other approaches are possible, too.

Your code

(defmacro do-primes ((var startv endv) &body body) `(my-func ,startv ,endv) `(,@body)) 

Your macro has two subforms. Why? The first form is computed and then returned into nowhere. The result will be garbage collected, because it is not used.

The second form

`(,@body)` 

will be computed and the return value will be the returned code. It does not make sense as such. Parentheses don't group statements and there is no iteration.

Sign up to request clarification or add additional context in comments.

Comments

2

Macros can be quite tricky. This is why when you try to debug them, the first thing that you should do is macroexpand them. (In Emacs there is a shortcut for that: C-c RET) You can also type (macroexpand [your macro usage here]) in the REPL. In your case you should type:

 (macroexpand '(do-primes (n 5 15) (fresh-line) (princ n))) 

Which yields ((FRESH-LINE) (PRINC N)).

Since (fresh-line) is not a function name - fresh-line is, you get that error.

Comments

1

You should check the example here:

http://www.gigamonkeys.com/book/macros-defining-your-own.html

I guess, it will explain everything you need.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.