1

I have an assignment where I need to write a script using lisp. I am having issues with passing variables

Here is the code. Issues to follow:

(defmacro while (test &rest bodies)
   `(do ()
        ((not ,test))
        ,@ bodies)
) 
(defmacro += (var inc)
    `(print (eval var))
    ;(setf (eval var) (+ (eval var) inc))
)

(defmacro iterate (i begin end inc &rest others)
    (setf i begin)
    
    (while (<= i (eval end))
        ;(dolist (item others)
        ;    (eval item)
        ;)
       
        (print (list 'two i (eval end)))
        (+= (eval end) 1)
        (setf i (+ i inc))
    )
)

(setf n 5)
(iterate i 1 n 1
    (print (list 'one i))
    (+= n 1)
)

The first issue lies in passing the statements to the iterate macro. When I try to run the commented out dolist, the print statement will throw an error when it comes to the variable i. For some reason I can not get it to print using the macro variable i which has a value, but it seems to want to default to the global variable i which has not been set. I get the error:

- EVAL: variable I has no value

The second issue is when I call the "+=" macro. The value of end in the iterate macro is 5 as passed to the macro by use of the variable N which it is set to 5, however, when I pass it to the "+=" macro using the line "(+= (eval end) 1)" I can not get it to pass the value. I tried removing the eval in the line "(+= (eval end) 1)" and when I try printing it with "(print (eval var))" in the "+=" macro, I get the error - EVAL: variable END has no value

How would I solve these issues?

2
  • 1
    your ITERATE macro is wrong. It should generate code, but it doesn't. Then there will also be no reason to use EVAL. Commented Apr 18, 2021 at 6:20
  • A good rule of thumb is: 'if you are using eval you are making a mistake'. There are cases where eval is justified, but they are not common, at all. Commented Apr 18, 2021 at 10:37

1 Answer 1

2

Your first macro is basically correct. It generates code.

(defmacro while (test &body body)
  `(do ()
       ((not ,test))
     ,@body))

One can check it with an example. We expand the macro using example code. The function MACROEXPAND-1 expands the top-level macro exactly once. You need to pass code to the function MACROEXPAND-1:

CL-USER 1 > (macroexpand-1 '(while (< i 10)
                              (print i)
                              (incf i)))
(DO NIL               ; NIL is the same as ()
    ((NOT (< I 10)))
  (PRINT I)
  (INCF I))
T
 

The generated code is a DO loop. Just like intended.

Thus we can use your macro:

CL-USER 2 > (let ((i 5))
              (while (< i 10)
                (print i)
                (incf i)))

5 
6 
7 
8 
9 
NIL

Your other macros should be like that

  • they should generate code
  • macro expansion of examples should show the right generated code
  • the generated code should work

Your macros should NOT

  • be using EVAL
  • try to compute results other than code
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.