why would evaluate the comparison? The comparison is a symbol, which a name for the function. Just use that symbol and insert it into the code.
(defmacro for ((param-name start-value end-value &optional (step1 1)) &body body)
(let* ((func-name (gensym))
(comparison (if (< step1 0) '<= '>=))
(start (gensym))
(end (gensym))
(step (gensym))
(k (gensym)))
`(let ((,start ,start-value)
(,end ,end-value)
(,step ,step1))
(labels ((,func-name (,param-name ,k)
(if (,comparison ,end ,param-name)
(progn (progn ,@body)
(,func-name (+ ,param-name ,step)
(1+ ,k)))
,k)))
(,func-name ,start 0)))))
If you actually want to make sure that function does not get redefined, you need to understand that functions and variables are in different namespaces. You would need to get a function object and funcall it.
(defmacro for ((param-name start-value end-value &optional (step1 1))
&body body)
(let* ((func-name (gensym))
(comp (gensym))
(comparison (if (< step1 0) '#'<= '#'>=))
(start (gensym))
(end (gensym))
(step (gensym))
(k (gensym)))
`(let ((,start ,start-value)
(,comp ,comparison)
(,end ,end-value)
(,step ,step1))
(labels ((,func-name (,param-name ,k)
(if (funcall ,comp ,end ,param-name)
(progn (progn ,@body)
(,func-name (+ ,param-name ,step)
(1+ ,k)) ) ,k)))
(,func-name ,start 0)))))
But you don’t need that.
If you want to debug macros, you need to see the expansion. Do it like this:
CL-USER 14 > (pprint
(macroexpand
'(for (i start end)
(print i))))
(LET ((#:G1788 START) (#:G1789 END) (#:G1790 1))
(LABELS ((#:G1787 (I #:G1791)
(IF (>= #:G1789 I)
(PROGN
(PROGN (PRINT I))
(#:G1787 (+ I #:G1790) (1+ #:G1791)))
#:G1791)))
(#:G1787 #:G1788 0)))
Common Lisp is a bit like an onion. There are different layers of language and the inner layers date back to the first Lisp implementation from 1958. It’s grown over decades.
A beginner is now confronted with history and inconsistencies. On the positive side a goal was not to throw away useful older applications or libraries, they could be ported over the different generations of Lisp. Same for the book. If you read a CL introduction from the mid 80s it’s still mostly valid, but lacks newer stuff. It’s also the implementations: some SBCL code may date back to the early 80s, with Spice Lisp, which was started even before Common Lisp existed.
At that time PROG was a widely used control structure for imperative programming. PROG1, PROG2 and PROGN were a bit similar and indicate in the name which result is returned.
You walk in a street, where some house are a few hundred years old and some are relatively new, using different building styles.