For arbitrary MIT Scheme programs, there isn't any way to do this. One problem is that the function you describe just can't work. For example, this doesn't use the 'scheme primitive' and
:
(let ((and 7)) (+ and 1))
but it certainly uses the symbol 'and
.
Another problem is that lots of things, like and
, are special forms that are implemented with macros. You need to know what all of the macros in your program expand into to figure out even what variables are used in your program.
To make this work, you need to restrict the set of programs that you accept as input. The best choice is to restrict it to "fully expanded" programs. In other words, you want to make sure that there aren't any uses of macros left in the input to your free-variables
function.
To do this, you can use the expand
function provided by many Scheme systems. Unfortunately, from the online documentation, it doesn't look like MIT Scheme provides this function. If you're able to use a different system, Racket provides the expand
function as well as local-expand
which works correctly inside macros.
Racket actually also provides an implementation of the free-variables
function that you ask for, which, as I described, requires fully expanded programs as input (such as the output of expand
or local-expand
). You can see the source code as well.
For a detailed discussion of the issues involved with full expansion of source code, see this upcoming paper by Flatt, Culpepper, Darais and Findler.