Pyli/Scoping
Contents
Overview
Pyli has two separate namespaces: the lexical namespace, and the dynamic namespace.
Lexical Namespace
The lexical namespace starts with whatever is defined in the let or fn parameters, and then precedes up according to where it was defined.
(define &a 6) (let [[&a 5]] &a) -> 5
Here are the useful functions:
define
define defines a new lexical variable at the highest level, or if one is already there, overwrites it.
(define name value ...)
The name should be a string. A good shortcut is to simply pre-pend a '&' to the word as in "&var". You could also use quotes, such as "var". Note that any string is valid, unless they are a built-in.
set!
set! is a very versatile function. It allows you to change the value of an existing variable.
(set! variable-expression value)
To change the value of a lexical variable, simply pass in the name of the lexical variable to set! as the variable-expression.
The variable-expression can be any number of things. See set! for the complete list.
let
fn
named-fn
defn
Dynamic Scope
Pyli allows dynamic scoping, but it has to be explicit.
The dynamic namespace is entirely separate from the lexical namespace. They may share variables of the same name, but they never refer to the same value except by coincedence.
The function dynamic will look up a variable in the dynamic scope, starting with the caller.
(dynamic &foo) # Returns the value of foo in the dynamic namespace.
let creates variables in the dynamic namespace if they are a pair with the first item being &dynamic. You can mix this with regular let declarations.
(let [[&(dynamic &name) value] ...] &body ...)
To change values in the dynamic namespace, use the idiom (set! &(dynamic &name) value). See set!.
Example: The following will return 3 after the last expression.
(define &a 1) (let [[&a 2]] &(defn a-fn &() &(dynamic-lookup &a))) (let [[&a 3]] &(a-fn))
Hiding Variables
(TODO: Do we really need this?)
It is possible to hide certain variables. These variables will not be seen by child environments.
(hide [[&var value] ...] &body ...) (dynamic-hide [[&var value] ..] &body ...)
Freezing Variables
freeze
freeze locks a lexical variable so that its value cannot be redefined unless it is first thawed. The built-ins are all frozen after they are initialized. Freeze also works on &(dynamic &name) expressions.
(freeze name ...)
name is any value that is valid for define.
(define &foo 5) (set! &foo 7) # OK, since it is not frozen. (freeze &foo) (set! &foo 8) # signals NameError, can't modify that variable since it is frozen. (thaw &foo) (set! &foo 8) # OK, since it has been thawed.
thaw
thaw reverses a freeze. See freeze above for an example.
(thaw name ...)
name is any value that is valid for define.
Related Variables
- *env*: The current environment, which contains both lexical and dynamic variables. An Environment.
- *global-env*: global environment, or the most senior lexical scope. An Environment.
- *parent-env*: The parent environment, lexically speaking. Lexical names will look at the *parent-env* next. An Environment.
- *calling-env*: The parent environment, dynamically speaking. Dynamic lookups will look at the *calling-env* next. An Environment.
- *vars*: The lexical variables defined in this environment with their values. A vector of vector pairs.
- *dynamic-vars*: The dynamic variables defined in this environment with their values. A vector of vector pairs.