0

I have written a function using the DO macro (using Peter Seibel's book as reference) but for some reason, when I compile my function:

(defun test ()
  (do ((n 2 (1+ n))
       (m 1 (1+ m))
       (a (1+ n))
       (b (1+ m))
       (c (+ n m)))
      ((= n 10) (* a b c))
      (print (* a b c))))

I get the following warning messages:

WARNING: in TEST in lines 1..10 : N is neither declared nor bound,
         it will be treated as if it were declared SPECIAL. 
WARNING: in TEST in lines 1..10 : M is neither declared nor bound,
         it will be treated as if it were declared SPECIAL. 
WARNING: in TEST in lines 1..10 : N is neither declared nor bound,
         it will be treated as if it were declared SPECIAL. 
WARNING: in TEST in lines 1..10 : M is neither declared nor bound,
         it will be treated as if it were declared SPECIAL.

When I try to execute test, it says that n has no value.

I am under the impression that the order of binding doesn't matter, but I tried rearranging it anyway and still received the same result.

What am I missing here?

I am using CLISP 2.49

Gab
  • 1,007
  • 9
  • 22
  • The bindings created by `DO` are not visible to the init-forms in that `DO`. You might want `DO*` instead, but I'm not sure what the loop is supposed to do. The variables `A`, `B` and `C` don't have step-forms, so their values don't ever change. Maybe you're missing init-forms for those? – jkiiski Sep 14 '17 at 19:48
  • @jkiiski Thanks for the comment. I didn't know that they weren't available in the init-form. I figured since I could use them in the step form, it would be available everywhere :/ As for the purpose of the loop, I removed the body and return value for the sake of the question. It makes sense in the context! What would you suggest I do to work around the init form restriction? – Gab Sep 14 '17 at 19:51
  • Using `DO*` instead of `DO` should work, unless you need the step-forms to all be evaluated before any assignments (which doesn't seem to be the case, unless you have more variables not shown in the code). – jkiiski Sep 14 '17 at 19:56
  • @jkiiski Thanks a lot for the answer. You should write a summary of the comments as an answer so I can give you some credit for it. – Gab Sep 14 '17 at 19:57

1 Answers1

3

DO evaluates all init-forms for the variables before creating any variable bindings. That means the bindings are not visible to init-forms in the same DO.

The code should work using DO* instead, although the output isn't very interesting since A, B and C never change.

(defun test ()
  (do* ((n 2 (1+ n))
        (m 1 (1+ m))
        (a (1+ n))
        (b (1+ m))
        (c (+ n m)))
       ((= n 10) (* a b c))
    (print (* a b c))))

(test)
; 18 
; 18 
; 18 
; 18 
; 18 
; 18 
; 18 
;=> 18

DO* is otherwise the same as DO, but it evaluates and establishes the bindings one by one, so you can refer to the previous variables in the init-forms. The same is done when updating the variables with the step-form.

jkiiski
  • 8,206
  • 2
  • 28
  • 44