Search code examples
emacslisp-macros

Conditionally remove let-binding in lisp macro


How can I conditionally remove a let-binding in a defun created in a lisp macro? Here, I want to remove the first let-bound variable from the resulting function, but am running into a problem where I have a nil that sticks around in the let bindings, causing an error.

For example, the resulting function uses let or let* and should remove the first variable assignment depending on arg. But the way I have it written the problem comes from replacing var1 with nil. I'm not sure how to get rid of the nil.

(cl-defmacro mac (cmd &optional arg)
  (let ((fn (intern (concat "fn-" cmd))))
    `(defun ,fn ()
       (interactive)
       (,(if arg 'let* 'let)
        (cons
         ,(when arg
            '(var1 1))
         (var2 (if (bound-and-true-p var1) (+ var1 1) 1)))
        (message "%s" var2)))))

(mac "fun")    ; Attempt to set constant: nil
(mac "fun2" t) ; no problem
;; (symbol-function 'fn-fun)
;; (symbol-function 'fn-fun2)
;; (fn-fun)
;; (fn-fun2)

Solution

  • The easiest workaround is probably to use ,@(when arg '((var1 1))). ,@ is used to splice a list into the position. Since WHEN returns NIL if the condition fails, and NIL is the same as an empty list, the splice effectively ignores it. When the condition succeeds ((var1 1)) is returned, and (var1 1) is unwrapped by the splice.