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?
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– ndsrib2023年07月31日 05:58:53 +00:00Commented Jul 31, 2023 at 5:58 -
1@rainer-joswig Thank you always for revealing so many subtle aspects of CL. Thank you also for "This answer was written only using natural intelligence." Thank you. I am going to borrow this a lot from you.gsl– gsl2024年07月18日 05:07:41 +00:00Commented Jul 18, 2024 at 5:07
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
(binding
...
(bind a 1)
...
(bind b 2)
...))
Would expand to something like
(progn
...
(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
(binding
...
(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 binding
s rather than implicit progn
s 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.
Explore related questions
See similar questions with these tags.
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?destructuring-bind
is used to declare a bunch of variables whose values are members of a list (kind of like pattern matching).