-
Notifications
You must be signed in to change notification settings - Fork 2
First Class Environments
Another unusual feature that I'm playing with, the keyword env introduces and returns an environment as a
value. For example:
a = env {
fn square(x) {
x * x
}
b = env {
fn cube(x) {
x * x * x
}
}
}
The '.' operator takes an environment and an expression to evaluate in that environment. It binds more
tightly than function calling, so given the above:
define five = 5;
a.square(five); // 25
a.b.cube(2); // 8
Like fn, env can take an optional name as argument, so:
env a {
x = 4
}
defines a as the environment.
By default, the environment constructed by env extends the current environment. However it may be advantageous
to extend a different environment, so that we can have direct access to the content of that environment without
needing to qualify access with dot notation. The extends qualifier does this. For example
env utils {
fn square(x) {
x * x
}
}
env user extends utils {
fn test(x) {
square(x)
}
}
user.test(5);
is 25.
The same dot notation can be used in locating the environment to be extended, but for the time being at least the components of the environment are limited to simple symbols.
Another example:
a = env {
b = env {
fn cube(x) {
x * x * x
}
}
}
env user extends a.b {
fn test(x) {
cube(x)
}
}
user.test(4);
is 16.
Because nesting of environments can potentially shadow functions defined in enclosing environments, the
variable globalenv is provided as a convenience in the global environment and bound to the global
environment. To be honest that is not much different than just saying env globalenv {} at the top-level,
but it is ever so slightly more efficient (one less level of indirection.)
Here's a rather perverse example of it in action:
env a {
fn pair(ele, lst) { // shadows the global pair fn
globalenv.pair(ele, lst) // calls the global pair fn
}
}
a.pair(1, []);
is [1].
Up: Home
Next: Load
PyScheme, AKA F-Natural