8 Environments
An environment consists of a set of bindings, and a list of zero or more references to other environments called its parents. Changing the set of bindings of an environment, or setting the referent of the reference in a binding, is a mutation of the environment. (Changing the parent list, or a referent in the list, would be a mutation of the environment too, but there is no facility provided to do it.) The Kernel data type environment is encapsulated. Among other things, there is no facility provided for enumerating all the variables exhibited by an environment (which is not required, after all, to be a finite set), and no facility for identifying the parents of an environment. Two environments are equal? iff they are eq?.
An auxiliary data type used by combiners that perform binding is ignore. The ignore type consists of a single immutable value, having external representation #ignore. The ignore type is encapsulated.
The primitive type predicate for type environment.
environment?returns true iff all the objects inobjectsare of type environment.
The primitive type predicate for type ignore.
ignore?returns true iff all the objects inobjectsare of type ignore.
The
evalapplicative evaluatesexpressioninenvironment, as a tail context, returning the resulting value.
The applicative constructs and returns a new environment, with initially no local bindings, and parent environments the environments listed in
environments. The constructed environment internally stores its list of parents independent of the first-class listenvironments, so that subsequent mutation ofenvironmentswill not change the parentage of the constructed environment. If the provided listenvironmentsis cyclic, the constructed environment will still check each of its parents at most once, and signal an error if no binding is found locally or in any of the parents. No two objects returned by different calls tomake-environmentareeq?to each other.
<definiend>should be a formal parameter tree, as described below; otherwise, an error is signaled.The
$define!operative evaluates<expression>in the dynamic environment and matches<definiend>to the result in the dynamic environment, binding each symbol in definiend in the dynamic environment to the corresponding part of the result; the matching process will be further described below. The ancestors of the dynamic environment, if any, are unaffected by the matching process, as are all bindings, local to the dynamic environment, of symbols not in<definiend>. The result returned by$define!is inert.A formal parameter tree has the following context-free structure:
ptree:: symbol | #ignore | () | (ptree . ptree)That is, a formal parameter tree is either a symbol, or ignore, or nil, or a pair whose car and cdr referents are formal parameter trees. A formal parameter tree must also be acyclic, and no one symbol can occur more than once in it. It is not an error for a pair in the tree to be reachable from the root by more than one path, as long as there is no cycle; but if any particular symbol were reachable from the root by more than one path, that would count as occurring more than once. Thus, if a pair is reachable by more than one path, there must be no symbols reachable from it.
Matching of a formal parameter tree
tto an objectoin an environmenteproceeds recursively as follows. If the matching process fails, an error is signaled.
- If
tis a symbol, thentis bound tooine.- If
tis#ignore, no action is taken.- If
tis nil, thenomust be nil (else matching fails).- If
tis a pair, thenomust be a pair (else matching fails). The car oftis matched to the car ofoine, and the cdr oftis matched to the cdr ofoine.
<bindings>should be a finite list of formal-parameter-tree/expression pairings, each of the form(formals expression), where eachformalsis a formal parameter, and no symbol occurs in more than one of theformals.The following equivalence holds:
($let ((form1 exp1) ... (formn expn)) . objects) == (($lambda (form1 ... formn) . objects) exp1 ... expn)Thus, the
expkare first evaluated in the dynamic environment, in any order; then a child environmenteof the dynamic environment is created, with theformkmatched ineto the results of the evaluations of theexpk; and finally the subexpressions ofobjectsare evaluated inefrom left to right, with the last (if any) evaluated as a tail context, or ifobjectsis empty the result is inert.
Operative
$bindsevaluates<exp>in the dynamic environment; call the resultenv.envmust be an environment. The operative is a predicate that returns true iff all its later operands,<symbols>, are visibly bound inenv.
The
get-current-environmentapplicative returns the dynamic environment in which it is called.
The
make-kernel-standard-environmentapplicative returns a standard environment; that is, a child of the ground environment with no local bindings.
<bindings>should be a finite list of formal-parameter-tree/expression pairings, each of the form(formals expression), where eachformalsis a formal parameter tree;<body>should be a list of expressions.The following equivalences hold:
($let* () . body) == ($let () . body) ($let* ((form exp) . bindings) . body) == ($let ((form exp)) ($let* bindings . body))
<bindings>and<body>should be as described for$let.The following equivalence holds:
($letrec ((form1 exp1) ... (formn expn)) . body) == ($let () ($define! (form1 ... formn) (list exp1 ... expn)) . body)
<bindings>and<body>should be as described for$let*.The following equivalences hold:
($letrec* () . body) == ($letrec () . body) ($letrec* ((form exp) . bindings) . body) == ($letrec ((form exp)) ($letrec* bindings . body))
<bindings>and<body>should be as described for$let.The following equivalence holds:
($let-redirect exp ((form1 exp1) ... (formn . body) expn)) == ((eval (list $lambda (form1 ... formn) body) exp) expn ... expn)
<bindings>and<body>should be as described for$let.The following equivalence holds:
($let-safe bindings . body) == ($let-redirect (make-kernel-standard-environment) bindings . body)
Operative
$remote-evalevaluates<exp2>in the dynamic environment, then evaluates<exp1>as a tail context in the environment that must result from the first evaluation.
<bindings>should be as described for$let.The following equivalence holds:
($bindings->environment . bindings) == ($let-redirect (make-environment) bindings (get-current-environment))
stringshould be the external representation of a single object. If none or more than one external representation is found instringthen an error is signaled.Applicative
eval-stringreads an external representation from string, and evaluates the resulting object inenvironment, as a tail context, returning the resulting value.
<formals>should be as described for the$define!operative. The$set!operative evaluates<exp1>and<exp2>in the dynamic environment; call the resultsenvandobj. Ifenvis not an environment, an error is signaled. Then the operative matches<formals>toobjin environmentenv. Thus, the symbols of<formals>are bound inenvto the corresponding parts ofobj. The result returned by$set!is inert.
<symbols>must be a finite list of symbols, containing no duplicates.<body>must be a finite list.The
$provide!operative constructs a childeof the dynamic environmentd; evaluates the elements of<body>ine, from left to right, discarding all of the results; and exports all of the bindings of symbols in<symbols>frometod, i.e., binds each symbol indto the result of looking it up ine. The result returned by$provide!is inert.The following equivalence holds:
($provide! symbols . body) == ($define! symbols ($let () ($sequence . body) (list . symbols)))
<symbols>must be a list of symbols.The
$import!operative evaluates<exp>in the dynamic environment; call the resultenv.envmust be an environment. Each distinct symbolsin<symbols>is evaluated inenv, andsis bound in the dynamic environment to the result of this evaluation.The following equivalence holds:
($import! exp . symbols) == ($define! symbols ($remote-eval (list symbols) exp))