(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
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.
> 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.
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)?
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)).