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 inobjects
are of type environment.
The primitive type predicate for type ignore.
ignore?
returns true iff all the objects inobjects
are of type ignore.
The
eval
applicative evaluatesexpression
inenvironment
, 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 ofenvironments
will not change the parentage of the constructed environment. If the provided listenvironments
is 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-environment
areeq?
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
t
to an objecto
in an environmente
proceeds recursively as follows. If the matching process fails, an error is signaled.
- If
t
is a symbol, thent
is bound too
ine
.- If
t
is#ignore
, no action is taken.- If
t
is nil, theno
must be nil (else matching fails).- If
t
is a pair, theno
must be a pair (else matching fails). The car oft
is matched to the car ofo
ine
, and the cdr oft
is matched to the cdr ofo
ine
.
<bindings>
should be a finite list of formal-parameter-tree/expression pairings, each of the form(formals expression)
, where eachformals
is 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
expk
are first evaluated in the dynamic environment, in any order; then a child environmente
of the dynamic environment is created, with theformk
matched ine
to the results of the evaluations of theexpk
; and finally the subexpressions ofobjects
are evaluated ine
from left to right, with the last (if any) evaluated as a tail context, or ifobjects
is empty the result is inert.
Operative
$binds
evaluates<exp>
in the dynamic environment; call the resultenv
.env
must be an environment. The operative is a predicate that returns true iff all its later operands,<symbols>
, are visibly bound inenv
.
The
get-current-environment
applicative returns the dynamic environment in which it is called.
The
make-kernel-standard-environment
applicative 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 eachformals
is 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-eval
evaluates<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))
string
should be the external representation of a single object. If none or more than one external representation is found instring
then an error is signaled.Applicative
eval-string
reads 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 resultsenv
andobj
. Ifenv
is not an environment, an error is signaled. Then the operative matches<formals>
toobj
in environmentenv
. Thus, the symbols of<formals>
are bound inenv
to 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 childe
of 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>
frome
tod
, i.e., binds each symbol ind
to 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
.env
must be an environment. Each distinct symbols
in<symbols>
is evaluated inenv
, ands
is 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))