Standard ML: Confusion about Reference Cells - functional-programming

I'm reading Harper's Intro to SML and am a bit confused on reference cells. On p. 114, he gives the following example:
val r = ref 0
val s = ref 0
val _ = r := 3
val x = !s + !r
val t = r
val _ = t := 5
val y = !s + !r
val z = !t !r
"After execution of these bindings, x is bound to 3, y is bound to 5, and z is bound to 10."
Here's my trace of his code:
val r = ref 0 //allocates storage for r and sets to 0
val s = ref 0 //allocates storage for s and sets to 0
val _ = r := 3 //sets r = 3
val x = !s + !r //sets x = 0 + 3 = 3
val t = r //sets t = 3
val _ = t := 5 //sets t = 5
val y = !s + !r //sets y = 0 + 3 = 3
val z = !t !r //sets z = 5 + 3 = 8
My x is correct (3), but my y and z are both wrong (my y is 3 instead of 5 and my z is 5 instead of 10).
Where am I going wrong here?
Also, why is val _ = t := 5 necessary instead of simply t := 5?
Thanks,
bclayman

val t = r does not set t to 3. It sets t to be the same reference cell that r is.
Thus, when you do t := 5, you set both the contents of t and r to 5, since both contain the same reference cell.
As for your other question, t := 5 is a function call of the function := : 'a ref * 'a -> unit. Thus, t := 5 is an expression that evaluates to ().
val _ = t := 5 simply throws away the () and turns it into a declaration rather than an expression.

val t = r makes t an alias for r. They both refer to the same location in the store. Thus t := 5 has the side effect of changing the contents of the memory location that r refers to as well (since t and r refer to the same place). Hence
val y = !s + !t
sets y = 0 + 5 = 5.
You are correct that val _ = t := 5 is basically the same as t := 5, though the former suppresses output in the REPL (by discarding the value of the assignment expression).

Related

Declare multiple variable bindings in one line in SML

Is it possible to declare multiple variable bindings in one line in SML? For example, I have the following:
let
val m1 = [1]
val m2 = [2]
val m3 = [3]
in
{...}
end
I would like to condense this down to something like
let
val m1 = [1], m2 = [2], m3 = [3]
in
{...}
end
This syntax doesn't work, but is there a way to declare multiple variable bindings in one line like this?
Here are two ways:
- let val x = 1 val y = 5 in x + y end;
val it = 6 : int
- let val x = 1 and y = 5 in x + y end;
val it = 6 : int
I personally find the slight abuse of and more readable.
However, I think the "destructuring bind" method is more common than either of these, since it's also more generally useful.
- let val (x, y) = (1,5) in x + y end;
val it = 6 : int
- fun f x = (x, x + 2, x + 3);
val f = fn : int -> int * int * int
- let val (x, y, z) = f 3 in x + z end;
val it = 9 : int
You could create a tuple and immediately destructure it.
let
val (m1, m2, m3) = ([1], [2], [3])
in
...
end

Defining recursive relation in Maple by "for loop"

I'm trying to make a recursive relation by "for loop" in Maple. Suppose we have two sequences M[i](x) and N[i](x) which N[0](x)=x^2 and M[i](x)=N[i-1](x)+1 and N[i](x)=M[i](x)+2. So I tried this code:
N[0] := proc (x) options operator, arrow; x^2 end proc;
for i to 3 do M[i] := proc (x) options operator, arrow; N[i-1](x)+1 end proc; N[i] := proc (x) options operator, arrow; M[i](x)+2 end proc end do;
But it doesn't give the correct answer (e.g. N[1](x) must be x^2+3). By the way, for some reasons I have to define my functions by mapping x. Is there anyway to modify this code?
The rsolve command can easily handle this example, except that it expects functions of the independent variable i.
And what you have is equations involving functions of x (which doesn't bear on the recursion), with i only appearing as an index.
You can rewrite the equations as functions of i, call rsolve, and then resubstitute back for the original functions.
It would be little effort to construct the substituion set S below by simply entering it in by hand. But for fun I construct it programmatically.
restart;
R1 := N[0](x) = x^2;
2
R1 := N[0](x) = x
R2 := M[i](x) = N[i-1](x)+1;
R2 := M[i](x) = N[i - 1](x) + 1
R3 := N[i](x) = M[i](x)+2;
R3 := N[i](x) = M[i](x) + 2
S := map( u->u=op([0,0],u)(op([0,1],u)),
indets({R1,R2,R3},
specfunc(anything,{N,M})) );
S := {M[i](x) = M(i), N[0](x) = N(0), N[i](x) = N(i),
N[i - 1](x) = N(i - 1)}
newEqs := eval( {R1,R2,R3}, S );
2
newEqs := { M(i) = N(i - 1) + 1, N(0) = x , N(i) = M(i) + 2 }
newV := eval( {N[i](x),M[i](x)}, S );
newV := {M(i), N(i)}
tempans := rsolve( newEqs, newV );
2 2
tempans := { M(i) = x + 3 i - 2, N(i) = x + 3 i }
ans := eval( tempans, map(rhs=lhs,S) );
2 2
ans := { M[i](x) = x + 3 i - 2, N[i](x) = x + 3 i }
Having constructed equations for the general forms of M[i](x) and N[i](x) you can evaluate either of those at specific cals of i. You can also create procedures from those results, and assign them. Eg,
for k from 1 to 3 do
N[k] := unapply(subs(i=k,eval(N[i](x),ans)), [x]);
end do:
N[3](11);
130
It seems inefficient to create all those operators (procedures separately). Why not create just on for N and one for M, that admits two arguments for i and x?
Nfunc := unapply(eval(N[i](x),ans), [i,x]);
2
Nfunc := (i, x) -> x + 3 i
Nfunc(3,x);
2
x + 9
Nfunc(3, 11);
130
[edited] I should tell you why your original attempt failed.
When you try your original attempt the i that appears within both of the procedure bodies is not simplified to the current value of the loop index i. And when you subsequently try and run any of the constructed procedures then it would just pick up whatever value the global i still had. There is no link between the index value of the name N[2] say and the i in its assigned procedure, whenever you subsequently call N[2](x).
restart;
N[0] := x -> x^2:
for i to 2 do
M[i] := x -> N[i-1](x)+1;
N[i] := x -> M[i](x)+2;
end do;
M[1] := x -> N[i - 1](x) + 1
N[1] := x -> M[i](x) + 2
M[2] := x -> N[i - 1](x) + 1
N[2] := x -> M[i](x) + 2
N[2](11); # why this result, you might asK
M[3](11) + 2
i; # still the value coming out of that do-loop
3
unassign('i');
N[2](11); # no relation between the 2 and the `i`
M[i](11) + 2
You could fix up your original by constructing a recursive sequence of procedures. The following "works". But it is incredibly inefficient at run-time because every call to any of the N[..] or M[..] procedures will recursively call into the others in the chain. And that whole recursive set of calls will happen every time you call it. That is to say, here the recursion occurs at run-time of each of the procedures.
restart;
N[0] := x -> x^2:
for i to 3 do
M[i] := subs(ii=i, x -> N[ii-1](x)+1);
N[i] := subs(ii=i,x -> M[ii](x)+2);
end do;
M[1] := x -> N[0](x) + 1
N[1] := x -> M[1](x) + 2
M[2] := x -> N[1](x) + 1
N[2] := x -> M[2](x) + 2
M[3] := x -> N[2](x) + 1
N[3] := x -> M[3](x) + 2
N[3](11);
130
The overall performance of running such a scheme would be very poor.
Much better would be to utilize the unapply command so that each of the N[i] and M[i] (for explicit i values) is a procedure that contains its explicit formula. When using unapply in the following way we pass it the function call which recursively evalutes to the respective formula. Here the recursion occurs only at construction time of each of the procedures.
restart;
N[0] := x -> x^2:
for i to 3 do
M[i] := unapply( N[i-1](x)+1, x);
N[i] := unapply( M[i](x)+2, x);
end do;
2
M[1] := x -> x + 1
2
N[1] := x -> x + 3
2
M[2] := x -> x + 4
2
N[2] := x -> x + 6
2
M[3] := x -> x + 7
2
N[3] := x -> x + 9
N[3](11);
130
But as I noted in my Answer above, there is no need to construct all those procedures at all. By utilizing the rsolve command we can solve the recurrence relation for the general formula (closed in terms of both i and x). And then from that closed formula we can utilize the unapply command to construct only one 2-argument procedure for N and one for M.

Value Bindings in SML? [duplicate]

This question already has answers here:
Value of bindings in SML?
(2 answers)
Closed 6 years ago.
Could someone please help. I don't get the sequence of evaluation here and how we got values of "ans". e.g. in the first example there's no value of y and I'm not sure whether this returns a pair or calls x ! (fn y => y x). It would be very helpful if you can Trace each expression.
val x = 1
val f = (fn y => y x)
val x = 7
val g = (fn y => x - y)
val ans = f g
val ans = 6 : int
=====================================
fun f p =
let
val x = 3
val y = 4
val (z,w) = p
in
(z (w y)) + x
end
val x = 1
val y = 2
val ans = f((fn z => x + z), (fn x => x + x + 0))
val ans = 12 : int
There are a few things which help make problems like this much clearer
when trying understand an alien function Lexical scoping works.
add in types to the parameters and return values without modifying the program, the compiler will tell you if you get it wrong...
replace anonymous functions with named ones.
rename variable bindings that have the same names but refer to different lexical scope.
remove variable bindings that only get used once.
binding a value to a name does not actually perform any computation,
so is merely for the benefit of the reader, if it is not doing that job
it merely serves to obfuscate, then by all means remove it.
fun f (y1 : int -> 'a) = y1 1 : 'a;
fun g (y2 : int) = 7 - y2 : int;
val ans : int = f g;
so g is given as a parameter to f, f calls g giving it the parameter x having the value 1 making y2 = 1, which g subtracts 7 - 1 returning 6.
the return value of g is an int, thus f's 'a type when g is applied to it is an int.
for the 2nd one clean it up a bit, I pulled the anonymous fn's out into their own and named values and call f (foo, bar) to make it more readable...
fun f p =
let val x = 3
val y = 4
val (z, w) = p
in (z (w y)) + x end
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
Finally, we can get rid of the let values which are only used once
and replace the (z,w) = p with just (z, w) as a parameter to the function which should be much easier to follow
fun f (z, w) = (z (w 4)) + 3
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
val ans = ((4 * 2) + 1) + 3

Difference in local & let scoping rule?

In the following example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
Is it true that local i is the same as local i = i?
Why cannot I do the same for while loop as such?
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
But have to use let:
Fs = cell(2)
i = 1
while i <= 2
let i = i
Fs[i] = ()->i
end
i += 1
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
When you introduce new variable, and try to get it's value before assignment, Julia throws an UndefVarError error, in the first example:
Fs = cell(2)
i = 1
for i = 1:2
local i # same as local i = i
Fs[i] = () -> i
end
println(Fs[1]()) # 1
println(Fs[2]()) # 2
println(i) # 1
For block introduces a new local i, adn for command itself assign it so the code successfully dose it's duty. But in the second example:
Fs = cell(2)
i = 1
while i <= 2 #LoadError: UndefVarError: i not define
local i = i
Fs[i] = ()->i
i += 1
end
A new i was introduced in while block, but before assignment you try to get it's value, and this produces an error.
In 3d one let command declare a new local block and a new i variable for it's block.
julia> function test3()
Fs = cell(2)
i = 1
while i <= 2
let i = 100
println(i)
end
i += 1
end
println(i)
end
test3 (generic function with 1 method)
julia> test3()
100
100
3# while block use the function's scope

Random function and calculating percentage

Using a random library with these functions:
randomChance(p) Returns true with the probability indicated by p.
randomInteger(low, high) Returns a random integer in the range low to high, inclusive.
what is the easiest way to implement a "random selector" that takes consideration of percentage, 1/4 or 1/3 etc... I got a array with key/value pairing. For example "a" migth have the value 2 and "b" have the value 2. 1/2 chance for both.
The max value will be the size of the array, cause it only contains unique items. The randomChance() function ranges between 0.0 - 1.0 where 1 = 100%. If my array size is, say 4. What is the best way of "letting 4 be 1".
Lets say you have:
a = 2, b = 2, c = 1, d = 3
now make it:
a = 2, b = 4, c = 5, d = 8
Create a random number from 1 to MaxVal (value of the last key, 8 in this example). Select the first Key where Value >= RandomNum
EDIT
I made a small VB.Net to show the algorithm and how it works. The code is not meant to be: Good, elegant, performant or readable.
Module Module1
Private Class Value
Public vOrg, vRecalc, HitCount As Integer
Public Key As String
Public Sub New(s, v1, v2, c)
Key = s : vOrg = v1 : vRecalc = v2 : HitCount = c
End Sub
End Class
Sub Main()
' set initial values
Dim KVP() As Value = {New Value("A", 2, 0, 0),
New Value("B", 2, 0, 0),
New Value("C", 1, 0, 0),
New Value("D", 3, 0, 0)}
' recalc values
For i = 0 To KVP.Length - 1
If i = 0 Then KVP(0).vRecalc = KVP(0).vOrg Else KVP(i).vRecalc = KVP(i).vOrg + KVP(i - 1).vRecalc
Next
' do test
Dim r As New Random
Dim runs As Integer = 1000 * 1000, maxval As Integer = KVP(KVP.Length - 1).vRecalc
For i = 1 To runs
Dim RandVal = r.Next(1, maxval + 1)
Dim chosen As Integer = (From j In Enumerable.Range(0, KVP.Length) Where KVP(j).vRecalc >= RandVal Take 1 Select j)(0)
KVP(chosen).HitCount += 1
Next
' ouput results
For Each kv In KVP
Console.WriteLine("{0} was chosen with {1:F3} propability, expected was {2:F3}", kv.Key, kv.HitCount / CDbl(runs), kv.vOrg / CDbl(maxval))
Next
Console.ReadLine()
End Sub
End Module
An output sample:
A was chosen with 0.250 propability, expected was 0.250
B was chosen with 0.251 propability, expected was 0.250
C was chosen with 0.124 propability, expected was 0.125
D was chosen with 0.375 propability, expected was 0.375
just multiply the randomChance() outcome and the array length together. It'll give you the index in the range [0,array_length-1] which you can use to access the array
array_index = (unsigned int)(randomChance(p) * (array_length - 1));
maybe you mean "letting 3 to be 1" (not 4) in your example. The last index of an array of length 4 is 3.

Resources