Search code examples
schemesicp

Simple library mechanism for scheme - import implementation


I implemented a basic scheme (think SICP). Now, I'd like to add a basic import/library functionality but have trouble coming up with a way to do that. I considered two approaches so far both suffering from the same obstacle.

In the old SICP (edition one) book there was a make-environment / package chapter which was also discussed here. This returns a new environment.

I would like to call something like

(import lib)

where lib either provides an environment or a list of procedure names and procedures. The question I have is how to programmatically extend the current environment with procedures that are provided by the library. Using something like a

((lambda (name proc) (define name proc)) 'test (lambda a (+ a a)))

is not going to work since define can not create a binding that is outside the scope of the lambda.

I have looked at the reference implementation of r6rs but was not able to figure out what the underlying mechanism for import is. How does it create the binding?

update 1

I think the underlying question (issue) I have is that it's not possible to use define within a lambda since the modification of the environment done through define is limited to the scope of the surrounding lambda. Is there a why programmatically define multiple (for example generated) procedures.

This works (similar to what is described here):

((eval `square-rrot scientific-lib) 4)

and this

(eval `(square-rrot 4) scientific-lib)

I can even write

(define sqrt (eval `square-root scientific-lib))

The above, however, is not sustainable, If I have a lib with 100 functions I can not define them one by one, I'd need a programmatic way to do that but I can not use something like:

((lambda (newName, libName) (define newName (eval libName scientific-lib))) sqrt `square-root)

It seems to me after reading the comments and answers that it is not possible based in stuff presented in SIPC. One needs more advanced stuff like define-syntax. Or am I wrong?


Solution

  • Here is how I did it in the end. Basically I departed from scheme and added a flag to lambda. A lambda can then either be scoped or not. The scoped lambda behaves as the usual lambda. In the case the lambda is not scoped I evaluate the body in an empty environment. This is then evaluated in the current environment. Something like this:

        if (lambdaHasAttribute(lambda, SCOPED)) {
            eenv = environment_extend(parameter, arguments, lambda_env);
            tmp = eval(lambda_body, eenv);
        } else {
            eenv = environment_extend(parameter, arguments, , mk_environment());
            /* scope arguments */
            tmp = eval(lambda_body, eenv);
            /* evaluate unscoped */
            tmp = eval(tmp, global_env);
        }