τ ::= ... | τ ref
e ::= ... | ref e | !e | e := e | l
Now, we need to make our states more interesting! While we've been talking about e -> e' being our transition relation from one expression to another expression for the whole class, this was a shortcut! Really, the "right way" to think about this transition relation is that the transition relation is from one state to another state, and before, our states were just expressions. Now, we need to add a store S to our state!
This is new - before, every expression e was something we imagined that the program might write down in the program. However, our new locations l are runtime artifacts, we don't allow the programmer to write them down, they only come into the program by way of rule e-alloc below.
Now our transition relation looks like (S,e) -> (S',e'). Let's look at how this changes some old rules.
(S,e1) -> (S',e'1)
-------------------------------------- e-app1
(S,e1 e2) -> (S',e'1 e2)
e1 value
(S,e2) -> (S',e'2)
-------------------------------------- e-app2
(S,e1 e2) -> (S',e1 e'2)
e2 value
-------------------------------------- e-appabs
(S, (λx:τ.e)e2) -> (S, [e2/x]e)
Now we can write the dynamic semantics for our langauge with seven rules. First for allocation ref e...
(S, e) -> (S', e')
-------------------------------------- e-ref
(S, ref e) -> (S', ref e')
e value
l fresh in S
-------------------------------------- e-alloc
(S, ref e) -> ((S, l=e), l)
Next for dereference !e:
(S,e) -> (S',e')
-------------------------------------- e-bang
(S,!e) -> (S',!e')
S(l) = e
-------------------------------------- e-deref
(S,!l) -> (S,e)
And finally for update e1 := e2
(S,e1) -> (S,e'1)
-------------------------------------- e-update1
(S,e1 := e2) -> (S,e'1 := e2)
e1 value
(S,e2) -> (S,e'2)
-------------------------------------- e-update2
(S,e1 := e2) -> (S,e1 := e'2)
e2 value
-------------------------------------- e-update
(S,l := e2) -> (S[l=e],*)
We need to change our judgment for types from [Σ]e : τ. We can look at how it changes our old rules:
[Σ]e1 : τ -> τ'
[Σ]e2 : τ
-------------------------------------- t-app
[Σ]e1 e2 : τ'
And then give the new rules!
Σ(l) = τ
-------------------------------------- t-loc
[Σ]l : τ ref
[Σ]e : τ
-------------------------------------- t-ref
[Σ]ref e : τ ref
[Σ]e : τ ref
-------------------------------------- t-bang
[Σ]!e : τ
[Σ]e1 : τ ref
[Σ]e2 : τ
-------------------------------------- t-update
[Σ]e1 := e2 : unit
Wrinkle: What is the typing rule for lambdas?
[Σ] x : τ |- [Σ]e : τ'
-------------------------------------- t-lambda Take 1
[Σ] λx:τ.e : τ -> τ'
Σ' extends &Sigma, [Σ'] x : τ |- [Σ]e : τ'
-------------------------------------- t-lambda Take 2 (Kripke)
[Σ] λx:τ.e : τ -> τ'
Our solution: x has no locations in it, so let's just say that
x:τ independently of anything else. Then we add a new
rule that tells us that if e : τ, then
[Σ]e : τ. This will shove all our work into
the substitution theorem.
x : τ |- [Σ]e : τ'
-------------------------------------- t-lambda
[Σ] λx:τ.e : τ -> τ'
x : τ
-------------------------------------- t-assume (t-var)
[Σ]x : τ