(progn (while-let ((run t)) (message "Running") (setf run nil)) (message "out of loop")) It ends in infinite recursion. setf/setq have no effect on the lexical variable. I tooka look, but I don't understand why is it necessary to build while-let on if-let. This simplified version did it for me: (defmacro while-let (spec &rest body) "Bind variables according to SPEC and conditionally evaluate BODY. Evaluate each binding in turn, stopping if a binding value is nil. If all bindings are non-nil, eval BODY and repeat. The variable list SPEC is the same as in `if-let*'." (declare (indent 1) (debug if-let)) (let* ((bindings (if (and (consp spec) (symbolp (car spec))) (list spec) spec)) (variables (mapcar #'car bindings))) `(let* ,bindings (while (and ,@variables) ,@body)))) (progn (while-let ((run t)) (message "Running") (setf run nil)) (message "out of loop")) => "out of loop" Or did I missunderstood how to use while-let in subr.el?