0
(setq x 1)

(defmacro dowhile (body condition)
  (cl-flet ((seq_eval (mylist) (cl-dolist (elt mylist result) (setq result (eval elt)))))
   (seq_eval body)
   (while condition (seq_eval body))))

(setq list_test '((setq x (1+ x))
                  (sit-for 2)
                  (message "Hello")))

(dowhile list_test (< x 10))

The above produces (wrong-type-argument listp list_test). According to the debugger, this happens during the following step:

  funcall((lambda
            (mylist)
            (let
                ((tail mylist))
              (while tail
                (let
                    ((elt
                      (car tail)))
                  (setq result
                        (eval elt))
                  (setq tail
                        (cdr tail))))
              result))
          list_test)

The error appears even if we use the form (setq list_test (list 'a 'b 'c)). Why exactly is it that, in that step, list_test isnt a list?

(The purpose of the above code is to implement a do-while loop that executes the body once before starting a normal while loop. It's meant to help me distinguish what code looks like when we use backquotes vs. when we don't)

1 Answer 1

1

It doesn’t matter what value the list_test variable has, because macros operate on syntax not values. The first argument to the dowhile macro is not the list stored in the list_test variable, it is simply the name list_test, which is not a list. See Chapter 14 Macros, which says:

“Macros” enable you to define new control constructs and other language
features.  A macro is defined much like a function, but instead of
telling how to compute a value, it tells how to compute another Lisp
expression which will in turn compute the value.  We call this
expression the “expansion” of the macro.

   Macros can do this because they operate on the unevaluated
expressions for the arguments, not on the argument values as functions
do.  They can therefore construct an expansion containing these argument
expressions or parts of them.
3
  • That clears it up! We need a (let ((var (eval macro_input)) ... in there
    – shintuku
    Dec 9, 2023 at 20:10
  • I wouldn’t do that, because then it has to be called with a variable name. You can’t call it with a real body any more. In fact, a macro should never call eval at all, because that evaluation will then be happening at compile time. You should instead generate code which contains the code to be evaluated.
    – db48x
    Dec 9, 2023 at 21:04
  • I see, thanks a lot for the help!
    – shintuku
    Dec 10, 2023 at 4:55

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.