In Common Lisp, we have to use the let form to declare a new lexically-scoped variable. This means that the code either looks like that written in C89 (all variables declared on top of scope), or acquires unreadably deep nesting. let* is somewhat useful, but is not always applicable.

Scheme 'solves' this problem by having a define form, that allows a lexical variable to be declared without creating a new nesting level.

So, the question is, is it possible to have Scheme-like variable declarations in Common Lisp, that do not increase the nesting level?

  • Of course, you could just write a macro that rewrites a list with let-like forms in them to the nested let-form.
    – Cubic
    Jul 28, 2023 at 10:25
  • @Cubic Right, but I wanted to make sure if there are some hidden gotchas with the obvious approach (considering I wasn't able to find any library that actually does that, despite people complaining about "Lots of Irritating Superfluous Parenthesis" since forever).
    – ndsrib
    Jul 28, 2023 at 10:30
  • I posted you question literally at ChatGPT and got an interesting answer, refering to destructuring-bind. Unfortunately, I am not a Common Lisp expert and cannot evaluate the quality of that answer - but maybe you try this by yourself?
    – Doc Brown
    Jul 28, 2023 at 11:06
  • @DocBrown Well, I can rejoice that ChatGPT isn't going to take my job then, since destructuring-bind is used to declare a bunch of variables whose values are members of a list (kind of like pattern matching).
    – ndsrib
    Jul 28, 2023 at 11:24

2 Answers 2


You don't have to use LET when using DEFUN: you can define local variables in the parameter list:

(defun foo (a)
  (let ((b (expt a 3)))
    (+ a b)))

is also

(defun foo (a &aux (b (expt a 3)))
  (+ a b))

That's not often seen in code, but it is a standard feature of Common Lisp.

Notice also that the syntax of LET and DEFUN is different in CL from what you are used to in Scheme: CL:LET allows declarations before the Lisp forms. CL:DEFUN allows documentation and declarations before the Lisp forms.

Note also that for example in Scheme R7RS small all internal DEFINE forms need to appear at the top of the enclosing form. Some Scheme implementations allow these forms to appear later in the body, but that is not in the R7RS small standard.

Disclaimer: This answer was written only using natural intelligence.

  • This is just like C89 however, where all variables have to be declared up front. Scheme's define provides for an alternative to both upfront declarations and deep nesting.
    – ndsrib
    Jul 31, 2023 at 5:58

Yes, of course this is possible: CL is a language which excels in creating new languages: that's what Lisps are for.

You could start with something like binding. This is a macro which works so that

  (bind a 1)
  (bind b 2)

Would expand to something like

  (let ((a 1))
    (let ((b 2))

and can bind local functions and so on.

This is a start but still requires wrapping the binding form around things. So for instance you need to write

  (bind a ...)
  (cond ((foo-p a)
         (binding ...))

And similarly in lots of cases. OK so you then write macros for variants of cond, defun, lambda & so forth such that they have bodies which are implicit bindings rather than implicit progns as they are in 'plain' CL. You call these macros, obviously cond &c and export them from your new CL/BINDING package which also reexports all the symbols from CL you do not wish to change.

Now you have a new language which does what you want.

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.