Reputation: 3128
I was studying references in SML.
I wrote the following code:
let
val f = (fn (s) => s := ref((!(!s)) + 2))
val x = ref (5)
val y = ref x
in
(f y ; !x)
end;
I'm trying to get to val it = 7 : int
, although my program prints val it = 5 : int
. I can't understand why. I am sure the problem is in the f
function but can't understand why.
What I'm trying to do: f
function should update the argument y
to be ref(ref(7))
so x
could be ref(7)
. but for some reason it doesn't work. What is the problem?
Upvotes: 1
Views: 398
Reputation: 16135
As Andreas Rossberg suggests, val f = fn r => !r := 7
could be one way to update the int of an int ref ref to 7. But instead of 7
you could write anything. If, instead, you want to increase by two the int being pointed indirectly to, a hybrid between your attempt and Andreas'es suggestion could be
fun f r = !r := !(!r) + 2
Here, !r := ...
means "dereference r
to get the int ref it points to, and update that int ref so that it instead points to ...
", and !(!r) + 2
means "dereference r
twice to get the int it indirectly points to, and add two to it." At this point, you have not changed what r
points to (like you do with s := ref ...
), and you're using the value it points to indirectly using the double-dereference !(!r)
.
A test program for this could be:
val x = ref 5
val y = ref x
fun f r = !r := !(!r) + 2
fun debug str =
print ( str ^ ": x points to " ^ Int.toString (!x) ^ " and "
^ "y points indirectly to " ^ Int.toString (!(!y)) ^ ".\n" )
val _ = debug "before"
val _ = f y
val _ = debug "after"
Running this test program yields:
before: x points to 5 and y points indirectly to 5.
after: x points to 7 and y points indirectly to 7.
Upvotes: 0
Reputation: 36118
Updating y to point to a new ref does not update x. There's a new reference created during the call to f, let's call it z. Before the call we have:
x -> 5
y -> x
where ->
is "points to". After the call it is:
x -> 5
y -> z
z -> 7
Edit: One possible way to actually update x is by defining f as follows:
val f = fn r => !r := 7
When invoking f y, this updates the reference pointed to by y, which is x. But whether that is the "right" solution depends on what you actually want to achieve.
Upvotes: 1