(* we don't handle cases where t1 doesn't evaluate to a Mutcell *)
let (Mutcell index1, s') = eval t1 g s
(* note that s' may be different from s, if t1 itself contained any mutation operations *)
- in let (new_value, s'') = eval t2 g s'
- (* now we create a list which is just like s'' except it has new_value in index1 *)
+ in let (value2, s'') = eval t2 g s'
+ (* now we create a list which is just like s'' except it has value2 in index1 *)
in let rec replace_nth lst m =
match lst with
| [] -> failwith "list too short"
- | x::xs when m = 0 -> new_value :: xs
+ | x::xs when m = 0 -> value2 :: xs
| x::xs -> x :: replace_nth xs (m - 1)
in let s''' = replace_nth s'' index1
(* we'll arbitrarily return Int 42 as the expressed_value of a Setref operation *)
(* we don't handle cases where t1 doesn't evaluate to a Pair *)
let (Pair (index1, index2), s') = eval t1 g s
(* note that s' may be different from s, if t1 itself contained any mutation operations *)
- in let (new_value, s'') = eval t2 g s'
- (* now we create a list which is just like s'' except it has new_value in index1 *)
+ in let (value2, s'') = eval t2 g s'
+ (* now we create a list which is just like s'' except it has value2 in index1 *)
in let rec replace_nth lst m =
match lst with
| [] -> failwith "list too short"
- | x::xs when m = 0 -> new_value :: xs
+ | x::xs when m = 0 -> value2 :: xs
| x::xs -> x :: replace_nth xs (m - 1)
in let s''' = replace_nth s'' index1
in (Int 42, s''')
type store = expressed_value list;;
-Our evaluation function still interacts with a `store` argument in much the same way it did with explicit-style mutation. The clause for `Variable ...` works differently, because all `expressed_value`s now need to be retrieved from the `store`:
+Our evaluation function still interacts with a `store` argument in much the same way it did with explicit-style mutation. The clause for `Variable (...)` works differently, because all `expressed_value`s now need to be retrieved from the `store`:
let rec eval (t : term) (g : assignment) (s : store) = match t with
...
in eval t3 g s''
;;
-Note that because the `savedg` component of a `Closure` keeps track of which `index`es in the store free variables were bound to, the values at those `index`es can later be changed, and later applications of the `Closure` will use the changed values.
+Note that because the `savedg` component of a `Closure` keeps track of which `index`es in the store---rather than which values---free variables were bound to, the values at those `index`es can later be changed, and later applications of the `Closure` will use the changed values.
The complete code is available [here](/code/calculator/calc6.ml).
##Adding Aliasing and Passing by Reference##
+Next we'll add aliasing as described at the end of [[week9]]. We'll also add the ability to pass (implicit) reference cells as arguments to a function, which lets changes made within the function body be effective in the outside environment. When we discussed this in [[week9]], we proposed a different syntactic form for the function values that get called in this way. Instead of:
+
+ let f = lambda (y) -> ...
+ ...
+ in f x
+
+one would write:
+
+ let f = lambda (alias y) -> ...
+ ...
+ in f x
+
+Real programming languages that have this ability, such as C++, do something analagous. Here the function is declared so that *all* of its applications are expected to alias the supplied argument. You can always work around that in a particular case, though, like this:
+
+ let f = lambda (alias y) -> ...
+ ...
+ in let y = x ; creates new (implicit) reference cell with x's value
+ in f y
+
+In our present framework, it will be easier to do things differently. We will
+introduce a new syntactic form at the location where a function value is
+applied, rather than in the function's declaration. We say:
+
+ Let ('f',
+ Lambda ('y', ...),
+ ...
+ Apply(Variable 'f', Variable 'x')...)
+
+for the familiar, passing-by-value behavior, and will instead say:
+
+ Let ('f',
+ Lambda ('y', ...),
+ ...
+ Applyalias(Variable 'f', 'x')...)
+
+for the proposed new, passing-by-reference behavior. (Besides being easier to implement here, this strategy also has the advantage of more closely aligning with the formal system Jim discusses in his "Hyper-evaluativity" paper.) Note that the second parameter to the `Applyalias` form is just `'x'`, not `Variable 'x'`. This is because (1) only variables are acceptable there, not arbitrary expressions, and (2) we don't need at that point to compute the variable's present value.
+
+Here is our expanded language:
+
type term =
Intconstant of int
| Multiplication of (term * term)
| Applyalias of (term * char)
;;
+The definitions of `index`, `bound_value`, `assignment`, `expressed_value`, and `store` can remain as they were in the implementation of implicit-style mutation. Here are the changes to our evaluation function:
+
let rec eval (t : term) (g : assignment) (s : store) = match t with
...
| Alias (var_to_bind, orig_var, t3) ->