6.10.0.2
8 Modeling Imperative-Functional Languages
Goals |
— revise the language for assignment statements |
8.1 Syntax for Variable Assignment
Note
(set! x e) is not a binding construct.
8.2 Blocks Anybody?
For writing programs in this world, you’d also want blocks or local
declarations. But we don’t add those as syntax but as meta-functions:
Here are some sample programs:
How do they behave?
8.3 Reduction Rules for Imperative PCF
Today we use the call-by-value PCF to add variable assignment—simply for
variety not because there is anything inherently wrong about assignment
statements and call-by-name.
From PCF with function definitions, we know we need evaluation contexts for
both expressions and programs:
In particular, we need a new evaluation context for
set!.
Looking up variable values works just like looking up functions:
(--> (prog ((defvar x_1 v_1) ... (defvar x v) (defvar x_2 v_2) ...) |
(in-hole E-value x)) |
(prog ((defvar x_1 v_1) ... (defvar x v) (defvar x_2 v_2) ...) |
(in-hole E-value v)) |
retrieve) |
And this tells us that modifying what a variable stands for works in a
similar manner:
(--> (prog ((defvar x_1 v_1) ... (defvar x v) (defvar x_2 v_2) ...) |
(in-hole E-value (set! x v_new))) |
(prog ((defvar x_1 v_1) ... (defvar x v_new) (defvar x_2 v_2) ...) |
(in-hole E-value v)) |
set) |
But to make it all work, we need one more rule:
(--> (prog ((defvar x v) ...) (in-hole E-value ((lambda (x_1) e) v_1))) |
(prog ((defvar x v) ... (defvar x_1 v_1)) (in-hole E-value e)) |
(where (x_* ... x_1 x_& ...) (assignables e)) |
allocate) |
We call this allocate because in a language such as Racket
lambda
allocates a slot in the store for assignable variable bindings.
Note It would be easy to add deallocate rules and garbage-collection
rules as one-liners. To model stack de/allocation would be a bit harder but
still well within reach of Reduction Semantics.
After the presentation See figure 5 for the complete
reduction relation. Figure 6 shows the eval
function and its test suite. If you run this model, you will see that a
test fails. Why? See the end of the file for the answer.
Figure 5: The complete reduction semantics for defvar
Figure 6: The eval function for PCF plus defun
Answer The first test fails because the value inside of the final
prog refers to a variable in the defvar sequence. During our
discussions today, I often referred to load and unload
functions, which would make eval much more realistic. In this example,
an unload function would have to eliminate the defvar references
in a safe manner. What could "safe" mean here?