Re: Scope Question
- From: Kaz Kylheku <kkylheku@xxxxxxxxx>
- Date: Tue, 29 Apr 2008 19:41:45 -0700 (PDT)
On Apr 29, 3:14 pm, dstein64 <DStei...@xxxxxxxxx> wrote:
Wow, I should really learn more about the scoping rules in Lisp. Any
suggested readings?
Anyhow, here's my current scope question:
Suppose I have a recursive function that is searching for elements in
a tree. How can I store a list such that it is not reset on each
recursive call to the search function?
The number one solution is to split the recursion into a non-recursive
interface and a recursive implementation, and nest these inside each
other so that the recursive implementation can see lexical variables
established by the interface:
(defun nonrecursive-interface (input)
(let ((context (make-recursive-context input)))
(labels ((recursive-implementation (input)
;; can freely refer to context
... ))
(recursive-implementation input))))
The second best way is to use extra parameters. This can be done
without splitting the function into two, thanks to optional parameters
(defun recursive-function (input
&optional (context nil context-passed-p))
(if context-passed-p
(... this is a recursive call ...)
(... not passed, this is the top-level call ...)))
If the context is not passed, you must create one and then start the
recursion.
These are the ways to do it if the whole thing is under your control,
and there isn't a whole lot of code involved in the recursion loop.
If the recursion is complicated---for instance, involves lots of
functions, many of which are external to the module, and for various
reasons cannot be made to cooperate by passing through your extra
arguments and at the same time make lexical scoping impractical---then
you can use a dynamically scoped variable. You bind this dynamically
scoped variable around the recursion chain. In keeping with lisp
coding conventions, you should introduce the variable with DEFVAR or
DEFPARAMETER at file scope and give it a descriptive name which begins
and ends with an asterisk character. The most straightforward way to
set up the binding is to split the function into the interface wrapper
and a recursive implementation. The wrapper will encapsulate the call
to the implementation inside a LET which establishes the local binding
for the special variable. The recursive function can then make free
references to that variable; the variable is private.
;; The following creates top-level variable, and also
;; specially marks the *FOO-CONTEXT* symbol so that
;; whenever it is subject to a variable binding,
;; the binding will be dynamic rather than lexical.
(defvar *foo-context*)
(defun foo-recursion-helper (input)
;; free recursion
)
(defun foo-recursion (input)
(let ((*foo-context* (make-context input)))
(foo-recursion-helper input)))
Now FOO-RECURSION-HELPER can call some arbitrary chain of functions,
which ends up calling back into FOO-RECURSION-HELPER. That call will
still be able to use its *FOO-CONTEXT*.
.
- References:
- Scope Question
- From: dstein64
- Scope Question
- Prev by Date: Re: CLtL2 copyright question
- Next by Date: Re: Scope Question
- Previous by thread: Re: Scope Question
- Next by thread: iolib/ linux epoll and http servers
- Index(es):
Relevant Pages
|
|