I wrote a macro to execute several nested loops. I understand that there are other possibilities for this, but I'm trying to learn how to write macros, and this seemed like a good use case. It works too (sort of):
(defmacro dotimes-nested (nlist fn)
(let ((index-symbs nil)
(nlist (second nlist))) ;remove quote from the beginning of nlist
(labels
((rec (nlist)
(cond ((null nlist) nil)
((null (cdr nlist))
(let ((g (gensym)))
(push g index-symbs)
`(dotimes (,g ,(car nlist) ,g)
(funcall ,fn ,@(reverse index-symbs)))))
(t (let ((h (gensym)))
(push h index-symbs)
`(dotimes (,h ,(car nlist) ,h)
,(rec (cdr nlist))))))))
(rec nlist))))
works:
(macroexpand-1 '(dotimes-nested '(2 3 5)
outputs:
(DOTIMES (
(DOTIMES (
(DOTIMES (
(FUNCALL
and call the macro as follows:
(dotimes-nested '(2 3 5)
returns correctly what I expect:
0, 0, 0
0, 0, 1
0, 0, 2
0, 0, 3
0, 0, 4
0, 1, 0
0, 1, 1
0, 1, 2
0, 1, 3
0, 1, 4
0, 2, 0
0, 2, 1
0, 2, 2
0, 2, 3
0, 2, 4
1, 0, 0
1, 0, 1
1, 0, 2
1, 0, 3
1, 0, 4
1, 1, 0
1, 1, 1
1, 1, 2
1, 1, 3
1, 1, 4
1, 2, 0
1, 2, 1
1, 2, 2
1, 2, 3
1, 2, 4
2
However, if I call it this:
(let ((dims '(3 4)))
(dotimes-nested dims
#'(lambda (x y) (format t "~A, ~A~%" x y))))
I get an error message:
How to pass a variable that is not interpreted as a symbol, but as a value? Should I evaluate it in a macro using? But I can’t figure out how to do this. Also, how will both situations work: a: calling a macro with the literal '(3 4) and b: passing the character associated with the list' (3 4)? Do I need separate macros for each?
, .
nlist, (second nlist) . , , '(3 4) (quote (3 4)) . ? , , , ?