lisp programming

I recently had to touch go and came to know about defer statements which let you stack few function calls for execution just before the parent function exits, irrespective of how it actually exits. Something like this is also available in R in the guise of on.exit function. Here is an example from the chapter on functions in Advanced R:

in_dir <- function(dir, code) {
  old <- setwd(dir)
  on.exit(setwd(old))

  force(code)
}
getwd()

In an attempt to improve the defun experience in Emacs Lisp, I tried replicating the defer thing in a macro (also adding support for early return).

(defmacro defun+ (name lambda-list &optional docstring &rest body)
  "Regular defun with defer and return support"
  (let ((defers (make-symbol "defers")))
    `(defun ,name ,lambda-list
       ,docstring
       (block nil ;; This lets us use return expression
         (let ((,defers nil))
           (cl-macrolet ((defer (form) `(push '(funcall ,form) ,',defers)))
             (unwind-protect
                 (progn ,@body)
               (eval `(progn ,@,defers)))))))))

Now, we can do things like:

(defun+ some-func (x y)
  "hello"
  (defer (lambda () (print "the last deferred expression")))
  (defer (lambda () (print "second deferred")))
  (print "hello world")
  (if nil (defer (lambda () (print "unevaluated deferred"))))
  (defer (lambda () (print "this will be evaluated first")))
  (if t (return 33))
  (+ x y))

(print (format "Finally, the returned value is %s" (some-func 1 2)))