Is there a way to declare local variables in Lisp (avoiding let)?

let, lisp

Solution

Here's a proof of concept macro that pulls variable declarations from a flat list up into standard `let*` forms.

(defun my/vardecl-p (x)
  "Return true if X is a (VAR NAME VALUE) form."
  (and (listp x)
       (> (length x) 1)
       (eq 'var (car x))))

(defmacro my/defun (name args &rest body)
  "Special form of DEFUN with a flatter format for LET vars"
  (let ((vardecls (mapcar #'cdr
                          (remove-if-not #'my/vardecl-p body)))
        (realbody (remove-if #'my/vardecl-p body)))
    `(defun ,name ,args
       (let* ,vardecls
         ,@realbody))))

Example:

(my/defun foo (a b)
  (var x 2)
  (var y 3)
  (* x y a b))

(foo 4 5)
; => 120

Problem

I'm fond of Lisp, but one of the thing I find irksome about it is that it nests too much. In an imperative programming language, I can break a long expression by using an intermediate value, for instance: ``` int x = someFunctionCall() ? someOtherFunctionCall() : 42; int y = myUnterminableNameFunction(x); ``` instead of ``` int x = myUnterminableNameFunction(someFunctionCall() ? someOtherFunctionCall() : 42); ``` This can be done in Lisp too, but as far as I'm aware, only by using `let`. `let` introduces an additional level of nesting, which I'd rather avoid. I'm not looking to argue that opinion, but to find a way to declare local variable in a single, non-nesting function/macro call. Something like `declare_local` in the following: ``` (defun my_function (a b) (declare_local x (if (some_function_call) (some_other_function_call) 42)) (my_unterminable_name_function x)) ``` If it does not exist, can it maybe be implemented via a clever macro, without it being detrimental to performances?

Original source