Kaz Kylheku
8/7/2015 8:17:00 PM
On 2015-08-07, nandryshak@gmail.com <nandryshak@gmail.com> wrote:
> This is the macro I have written right now:
>
> (defmacro with-progress (message &rest body)
> (let ((progress '(princ "..")))
> `(progn
> (format t "~A" ,message)
> (loop for form in ',body
> do (prog
> (eval ',progress)
> (eval form)))
> (format t "Done.~%"))))
>
> Any tips?
The loop has to be executed during macro-expansion, not inserted
into the output! That's all, pretty much.
The loop has to interpose the progress among the forms,
and then the resulting list of forms has to be spliced into
the (progn ...).
The DO clause of LOOP takes multiple forms; no prog needed.
Anyway, we will need a COLLECT clause, or more likely APPEND.
(defmacro with-progress (message &rest body)
(let ((progress '(princ "..")))
`(progn
(format t "~A" ,message)
,@(loop for form in body
appending `(,progress ,form))
(format t "Done.~%"))))
See, the loop is unquoted (unquote spliced) so we just
refer to the body variable as body, not ,body.
The progress/form pair is constructed with backquote again,
and so those variables are referred to using unquoting.
We could replace that little backquote with (list progress form).
A minor correction in the end, as you can see.
To test your macro, use macroexpand first. Is the expansion correct?
If the expansion looks right, only then try running it:
[9]> (macroexpand '(with-progress "foo"))
(PROGN (FORMAT T "~A" "foo") (FORMAT T "Done.~%")) ;
T
[10]> (macroexpand '(with-progress "foo" X))
(PROGN (FORMAT T "~A" "foo") (PRINC "..") X (FORMAT T "Done.~%")) ;
T
[11]> (macroexpand '(with-progress "foo" X Y))
(PROGN (FORMAT T "~A" "foo") (PRINC "..") X (PRINC "..") Y (FORMAT T "Done.~%")) ;
T
[12]> (macroexpand '(with-progress "foo" X Y Z))
(PROGN (FORMAT T "~A" "foo") (PRINC "..") X (PRINC "..") Y (PRINC "..") Z
(FORMAT T "Done.~%")) ;
T