Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Common Lisp idiosyncrasies

2 views
Skip to first unread message

Rodrigo Ventura

unread,
Dec 7, 1998, 3:00:00 AM12/7/98
to

I know that a let construct can locally change the value of a
special variable, where this value is propagated to places outside of
the let lexical scope. For instance:

(defun aaa (x) (+ x sp))
(defparameter sp 123)

> (aaa 1)
124
> (let ((sp 2)) (aaa 3))
5

My question is: how can I attain the same kind of behavior with
functions, say, flet. For instance:

(defun foo () 'base)
(defun bar () (list (foo)))

> (foo)
BASE
> (bar)
(BASE)
> (labels ((foo () 'local)) (cons (foo) (bar)))
(LOCAL BASE)
> (flet ((foo () 'local)) (cons (foo) (bar)))
(LOCAL BASE)

And I wanted to have (LOCAL LOCAL) instead! Is it possible?

My view is: the first "let" example resembles dynamic scoping,
but lisp is lexical scoped by nature. And in the second case, it
would really require a dynamic scope behavior. Am I right?

Regards,

--
--

*** Rodrigo Martins de Matos Ventura, alias <Yoda>
*** yo...@isr.ist.utl.pt, http://www.isr.ist.utl.pt/~yoda
*** Teaching Assistant and MSc. Student at ISR:
*** Instituto de Sistemas e Robotica, Polo de Lisboa
*** Instituto Superior Tecnico, Lisboa, Portugal
*** PGP Public Key available on my homepage
*** Key fingerprint = 0C 0A 25 58 46 CF 14 99 CF 9C AF 9E 10 02 BB 2A

Barry Margolin

unread,
Dec 10, 1998, 3:00:00 AM12/10/98
to
In article <87lnkky...@pixie.isr.ist.utl.pt>,

Rodrigo Ventura <yo...@isr.ist.utl.pt> wrote:
> My view is: the first "let" example resembles dynamic scoping,
>but lisp is lexical scoped by nature. And in the second case, it
>would really require a dynamic scope behavior. Am I right?

Correct. Special variables are dynamically scoped, but there's no
dynamic scoping for function names.

You can get what you want by using UNWIND-PROTECT:

(let ((old-function (symbol-function 'foo)))
(unwind-protect
(progn
(setf (fdefinition 'foo)
#'(lambda () 'local))
(cons (foo) (bar)))
(setf (fdefinition 'foo) old-function)))

If you need to do this much, you could turn it into a macro:

(defmacro dynamic-flet (bindings &body body)
(let* ((saves
(loop for (fname) in bindings
collect `(,(gensym) (symbol-function ',fname))))
(settings
(loop for (fname . fval) in bindings
collect `(fdefinition ',fname)
collect `#'(lambda ,@fval)))
(restores
(loop for (fname) in bindings
for (gensym) in saves
collect `(fdefinition ',fname)
collect gensym)))
`(let (,@saves)
(unwind-protect
(progn (setf ,@settings)
,@body)
(setf ,@restores)))))

Caveat: in a multi-threaded Lisp, this will affect the bindings in all the
threads. Some of them may provide a LETF construct (it might have a
different name) that implements dynamic bindings to any SETFable place,
which hopefully interacts with threads properly. In that case,
DYNAMIC-FLET could simply be:

(defmacro dynamic-flet (bindings &body body)
`(letf (,@(loop for (fname . fval) in bindings
collect `((fdefinition ',fname)
#'(lambda ,@fval))))
,@body))

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.

Kent M Pitman

unread,
Dec 10, 1998, 3:00:00 AM12/10/98
to
Barry Margolin <bar...@bbnplanet.com> writes:

> In article <87lnkky...@pixie.isr.ist.utl.pt>,
> Rodrigo Ventura <yo...@isr.ist.utl.pt> wrote:
> > My view is: the first "let" example resembles dynamic scoping,
> >but lisp is lexical scoped by nature. And in the second case, it
> >would really require a dynamic scope behavior. Am I right?
>
> Correct. Special variables are dynamically scoped, but there's no
> dynamic scoping for function names.
>

> You can get what you want by using UNWIND-PROTECT: [...]

All good advice, Barry, though a simpler solution might be just
actually use special variables and FUNCALL. The only thing you lose
in the process is the functional notation. And it's done so rarely in
my experience that having it flagged clearly by FUNCALL and *...*
variables may be worth doing just for code-documentation purposes.

Steve Gonedes

unread,
Dec 13, 1998, 3:00:00 AM12/13/98
to

Barry Margolin <bar...@bbnplanet.com> writes:

< If you need to do this much, you could turn it into a macro:
<
< (defmacro dynamic-flet (bindings &body body)
< (let* ((saves
< (loop for (fname) in bindings
< collect `(,(gensym) (symbol-function ',fname))))
< (settings
< (loop for (fname . fval) in bindings
< collect `(fdefinition ',fname)
< collect `#'(lambda ,@fval)))
< (restores
< (loop for (fname) in bindings
< for (gensym) in saves
< collect `(fdefinition ',fname)
< collect gensym)))
< `(let (,@saves)
< (unwind-protect
< (progn (setf ,@settings)
< ,@body)
< (setf ,@restores)))))

Would a single unwind-protect cover all the cleanup forms if they
were like

(progn (setf ...) (setf ...)),

or is that why you used just a single setf (neat idea)?


Barry Margolin

unread,
Dec 15, 1998, 3:00:00 AM12/15/98
to
In article <m2n24s4...@KludgeUnix.com>,

Steve Gonedes <jgon...@worldnet.att.net> wrote:
>Would a single unwind-protect cover all the cleanup forms if they
>were like
>
>(progn (setf ...) (setf ...)),

Sure. The unwind-protect covers the entire protected form.

>or is that why you used just a single setf (neat idea)?

(setf a b c d) is semantically identical to (progn (setf a b) (setf c d)).

0 new messages