Zhiqing Liu <firstname.lastname@example.org> wrote:
| Is there a portable way to find if a variable is free in a Scheme
| environment? I don't think the following is portable:
| > a
| reference to undefined identifier: a
I was waiting to see if someone more authoritative would answer, but...
Basically, the answer is "No (but...)". Actually, I suspect you're not
asking the question you really want to be asking -- about "undefined" or
"unbound" variables, not a "free" ones.
As I understand it, the term "free" is usually only applied to the body of a
lambda expression. Yes, in the example you gave "a" itself is an "expression",
but that expression contains no binding forms. Thus in your example the
variable "a" will *always* be free in the expression "a", regardless of
whether it's currently defined or not.
Practically speaking, except as a question one might ask of an editor when
modifying source text, it's not going to be very useful to know at run-time
whether a given variable is "free" or not -- there's nothing you can *do*
about it in any case. Yes, you might call "eval" to do a top-level "define",
but that's fairly ugly, and anyway "eval" semantics aren't every portable
either. E.g., some take an environment as a 2nd arg and some don't. [And
besides, in a compiled environment all of the non-free variables may have
been renamed or turned into display offsets or something anyway, so you might
not even be able to *ask* the question...]
So I'm going to answer a different question, and hope it's what you were
really asking in the first place, namely:
During the progress of a Scheme "load" (or while typing S-exprs at a
top-level REPL) is there a portable way to find if a variable is currently
already defined in the top-level environment? Specifically, so that
a (re)definition of that variable can be "conditionalized" on its current
state of defined-ness, much like one does in languages like "C" with
The answer to that one is: "No, not really, but several Scheme implementations
give you something that's somewhat usable when trying to make code portable
among them." Here are some specific examples:
- MzScheme has a "defined?" procedure (ordinary primitive procedure), which
takes a symbol as an argument, and returns #t if the corresponding variable
is defined in the top-level environment. MzScheme does not consider lambda-
bound variables to be "defined" (probably because it internally "compiles"
expressions before evaluating them, and so the names of lambda-bound
variables have vanished before "defined?" could run).
- SIOD has a "symbol-bound?" procedure which works like MzScheme's "defined?".
- ELK has a "bound?" procedure, which takes a symbol as an argument, and
returns #t if the corresponding variable is defined in the top-level
environment *or* if it is lexically-bound/lambda-bound, unlike the others.
- SCM has a "defined?" macro form (*not* a procedure), which takes a literal
variable name (*not* a symbol!!) as an argument, and returns #t if that
variable is defined in the top-level environment. Like MzScheme, SCM does
not consider lambda-bound variables to be "defined".
Now in SCM, (defined? '+) ==> #f and in the others (defined? '+) ==> #t,
so you can use that to tell them apart, so you can hack the difference as:
(if (defined? '+)
(define repl:defined? defined?)
(define (repl:defined? x) (eval (list 'defined? x))))
[yes, it's an ugly use of "eval", but I couldn't think of any better way
to do it] but then you still need to arrange [in an init file?] to get SIOD
to see (define defined? symbol-bound?) and Elk to see (define defined? bound?)
before running the above test. At that point, you can portably [well, among
those four!] do things like:
(if (not (repl:defined? 'some-lib-function))
Is that what you were asking?
Rob Warnock, 7L-551 email@example.com http://reality.sgi.com/rpw3/
Silicon Graphics, Inc. Phone: 650-933-1673 [New area code!]
2011 N. Shoreline Blvd. FAX: 650-933-4392
Mountain View, CA 94043 PP-ASEL-IA