Re: lazy-let & loop
Bruno Haible <[email protected]>
| Newsgroups | gmane.lisp.clisp.devel |
|---|---|
| Message-ID | <3298330.GXKRH2WazP@omega> |
Hi Sam,
> I wonder if something like "lazy-binding" could help: bind the variable
> but not initialize its value. until it is explicitly set, accessing it
> reaches up in the environment. This would require something like
> `lazy-let` with the following test case:
>
> --8<---------------cut here---------------start------------->8---
> (let ((a 1))
> (lazy-let (a b)
> (print a) ; prints 1
> (print b) ; error - unbound variable
> (setq a 10) ; inner binding of a is activated
> (print a) ; prints 10
> (setq b 22)) ; binding of b is activated
> (print b) ; error - unbound variable
> (print a)) ; prints 1
> --8<---------------cut here---------------end--------------->8---
>
> while it is easy to avoid `lazy-let` above by putting `let` after the
> second `print`, it is not so easy with `loop` because we need the
> binding to exist around the main `tagbody` but to do initialization in
> the preamble inside `tagbody`.
Your proposal introduces a new approach to scoping: Have the scope depend
on whether the access to a variable is a read or a write access.
While this may provide a small advantage in implementing LOOP, I believe
that it is a really bad idea in general.
1) The purpose of the scopes in the language definition is that by looking
a the (fully macroexpanded) source code of a function, the user can
tell to which binding a certain variable reference refers.
If the user furthermore has to _scan_ the source code for assignments,
this lookup is significantly more complicated.
2) What about conditional accesses?
(lazy-let (a)
(if (> (random) 0.5)
(setq a 10))
(lambda (a) (print a)))
3) There are forms which combine a read access and a write access, like
(INCF b).
Instead, maybe we should provide explicit control of the environment in
which a form will be evaluated/compiled. For example:
(let ((a 1))
(environment-let env-with-a
(let ((b 2))
(in-enviroment env-with-a (list a b)))))
will evaluate (list a b) in an environment that contains the binding of a
but not the binding of b. This would be equivalent to
(let ((a 1))
(let ((#:g1 (lambda () (list a b))))
(let ((b 2))
(funcall #:g1))))
Such a clisp specific set of special-operators ENVIRONMENT-LET and
IN-ENVIRONMENT could be emulated for other implementations through a
code walker.
Still, I don't know whether such a thing is really needed for the LOOP
macro, where we have a finite set of initforms and bindings.
> The problem with loop is that under certain circumstances we separate
> initializing and binding of a variable.
This is not a problem by itself. It is explicitly allowed by CLHS 6.1.1.4
"Implementations can interleave the setting of initial values with the bindings."
What I see as a problem is that users are not warned when they write
unportable code. That is, we should have a warning (in the spirit of
"gcc -fsanitize=undefined" for C) whenever the interpretation of an initform
actually depends on the environment.
Bruno
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
clisp-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-devel