The Environment Model
Step Relation¶
General Rules: don’t step on values; don’t step on variables
- Small/Single Step Relation:
e --> e', where e’ can be a value or another expression yet to be evaluated to a value - Multi-Step Relation:
e -->* e'is the reflexive closure of single step. It allows single step to be performed 0 or multiple times - Big-Step Relation:
e ==> vstep expressions to values through multi-step and stop when it becomes values.
Introduction¶
For sake of efficiency, it would be better to substitute lazily: only when the value of a variable is needed should the interpreter have to do the substitution. That’s the key idea behind the environment model. In this model, there is a data structure called the dynamic environment, which is a dictionary mapping variable names to values. Whenever the value of a variable is needed, it’s looked up in that dictionary. (空间换时间)
Instead of
e ==> v, we now have<env, e> ==> v, whereenvdenotes the environment, and<env, e>is called a machine configuration. That configuration represents the state of the computer as it evaluates a program:envrepresents a part of the computer’s memory (the binding of variables to values), anderepresents the program.
{}represent the empty environment,{x1:v1, x2:v2, ...}represent the environment that bindsx1tov1, etc.env[x -> v]represent the environmentenvwith the variablexadditionally bound to the valuevenv(x)represent the binding ofxinenv.
Evaluation¶
Trivially,
<env, x> ==> env(x)
<env, fun x -> e> ==> fun x -> eProblem¶
However, when we try to define the rules of function application, we run into trouble. Intuitively, we would write something like this, where we sort of “substitute” all the occurrences of x in e with v2 and get the result v.
<env, e1 e2> ==> v
if <env, e1> ==> fun x -> e
and <env, e2> ==> v2
and <env[x -> v2], e> ==> vlet x = 1 in let f = fun y -> x in let x = 2 in f 0According to our semantics thus far, it would evaluate as follows:
let x = 1would produce the environment{x:1}.
let f = fun y -> xwould produce the environment{x:1, f:(fun y -> x)}.
let x = 2would produce the environment{x:2, f:(fun y -> x)}. Note how the binding ofxto1is shadowed by the new binding.Now we would evaluate
<{x:2, f:(fun y -> x)}, f 0><{x:2, f:(fun y -> x)}, f 0> ==> 2 because <{x:2, f:(fun y -> x)}, f> ==> fun y -> x and <{x:2, f:(fun y -> x)}, 0> ==> 0 and <{x:2, f:(fun y -> x)}[y -> 0], x> ==> 2` because <{x:2, f:(fun y -> x), y:0}, x> ==> 2`The result is therefore
2.
However, this should evaluate to 1. Notice that we evaluated e1 in the current environment, or more formally, we used a dynamic scope here.
Dynamic vs. Static Scope¶
- Dynamic Scope: the body of a function is evaluated in the current dynamic environment at the time the function is called, i.e. it uses the latest binding
- Lexical Scope: the body of a function is evaluated in the old dynamic environment that existed at the time the function was defined.
Most modern languages use lexical scope.
Implementing Time Travel¶
We have to store the variable binding at the time the function was defined. We define a new data structure called “closure” with two parts: (|exp, env|), where exp is the expression we are concerned about, and env the environment when the expression was defined.
Since we only have to consider scope in function application, the exp in our closure must always be a function, denoted by fun x -> e. Therefore, we can also write our closure as (|x, exp, env|), where x is the argument name, e is the function body, and env is the environment when this function was defined. In fact, that’s how we define it when implementing the Environment Model.
When we use big-step relation in evaluation, we say the result must be a value. Here, we can consider closure to be the value evaluated from a function. <env, fun x -> e> ==> (| fun x -> e, env |)
Using closure, we can now correctly define evaluation of function applications. (defenv represents the environment when e1 was defined)
<env, e1 e2> ==> v
if <env, e1> ==> (| fun x -> e, defenv |)
and <env, e2> ==> v2
and <defenv[x -> v2], e> ==> v