Passing array into function, want the original unmodified array afterward - sml

I have a function that, as a side-effect, mutates an array that's passed in:
fun do_something (n: int, v: bool array) =
let
val i = ref 0
val count = ref 0
in while !i < n do
( if Array.sub (v, !i) then
Array.update (v, !i, false)
else
(count := !count + 1);
i := !i + 1
);
!count
end
When the function has ended I want the array to have its original contents again. How can I do that?

Related

Simple function with internal state

I would like to write a minimal function with an internal state.
It should have signature f: () -> () and the n-th time it is called should print the number n.
I imagine that refs are necessary, but I do not know how to use them to make such a function.
I found a solution with an external local reference
local val mem = ref 0 in
fun f () =
let val _ = mem := !mem + 1 in print (Int.toString (!mem)) end
end
A solution to a slightly different problem would be to generate the function
fun iter_int n =
let val i = ref 0
in fn () =>
let val j = !i
in i := !i + 1 ; j
end
end

Implementing binary search but can't find an element

I have a code in sml of binary search , the thing is when I search 20, output shows there is no element in an array even though array has 20.
I can't figure out why is this happening.
open Array;
fun binsearch (A, x) =
let val n = length A;
val lo = ref 0 and hi = ref n;
val mid = ref ((!lo + !hi) div 2);
in
while ((!hi - !lo > 1) andalso (x <> sub (A, !mid))) do
(
if x < sub (A, !mid) then hi := !mid - 1
else lo := !mid + 1;
mid := (!lo + !hi) div 2
);
if x = sub (A, !mid) then SOME (!mid)
else NONE
end;
open Array;
val A = fromList [~24, ~24, ~12, ~12, 0, 0, 1, 20, 45, 123];
binsearch (A, 20);
binsearch (A, ~24);
binsearch (A, 123);
Code can't search number 20.
The reason for this error is an off-by-one mistake in (!hi - !lo > 1) which should be either (!hi - !lo > 0) or (!hi - !lo >= 1).
ML is, however, intended to be a functional language. A more functional approach (i.e. without references and while loops) might look like this:
fun binsearch arr x =
let
val l = Array.length arr
fun subsearch arr x lo hi =
if lo > hi then NONE
else
let
val mid = (lo + hi) div 2
val v = Array.sub (arr, mid)
in
if x < v then subsearch arr x lo (mid-1)
else if x > v then subsearch arr x (mid+1) hi
else SOME mid
end
in
subsearch arr x 0 (l-1)
end;

OCaml, Collatz sequence, can't print the result

I am trying to make a program to compute the length of the Collatz sequence on all numbers from 1 to 100. Basically if I have an odd number I have to multiply it by 3 and add 1(n*3+1), and if I have a even number I need to divide it by 2(n/2) and then keep doing it untill it gets to 1 and in the end print out the count of times the number was either divided by 2 or multiplyed by 3 and added 1.
Here is what i have so far:
let stevec = ref 0;
let n = ref 1;
for i = 1 to 100 do
n := i;
while !n != 1 do
if (n mod 2 = 0) then
stevec := !stevec + 1;
n := !n / 2;
if (n mod 2 = 1) then
stevec := !stevec + 1;
n := 3 * !n + 1;
done
print_int (stevec);
done;;
After I run the code I get a syntax error and the print_int get underlined so i guess there is a problem with that but I'm not even sure about that.
There are several problems with your code, so let's take a look at it.
let stevec = ref 0;
let n = ref 1;
You shouldn't write that kind of code, as ; is an expression separator (and you are using it here as a declaration separator).
The right approach depends on wether you want your declaration to be local or toplevel.
(* local declaration *)
let stevec = ref 0 in
let n = ref 1 in
(* toplevel declaration *)
let stevec = ref 0;;
let n = ref 1;;
Then you typed while !n != 1 do. This shouldn't be used as you do physical inequality between your integers, whereas you want structural equality. Well, it will work too because of OCaml's behavior on integers but good practice requires you to use <> instead of !=.
Now let's look at your loop's body:
if (!n mod 2 = 0) then
stevec := !stevec + 1;
n := !n / 2;
if (!n mod 2 = 1) then
stevec := !stevec + 1;
n := 3 * !n + 1;
Notice the absence of any fi or closing bracket? That's because in OCaml, only the next expression after the then is executed. And precedence over ; doesn't go as you want it to. You can use parens or the more explicit begin ... end construction. To prove that the begin ... end works, I replaced your second test by a else statement.
if (!n mod 2 = 0) then
begin
stevec := !stevec + 1;
n := !n / 2;
end
else
begin
stevec := !stevec + 1;
n := 3 * !n + 1;
end
Finally while ... done being itself an expression, you should put a ; at the end of it.
And that's how you remove the errors from your code.
Yet...
This is clearly not the "right way" to do it in OCaml. The main perk of FP is its closeness to maths and you are here trying to define a mathematical function. So let's do this in a functionnal way:
let is_even x = (x mod 2) = 0;;
let rec collatz counter n =
if n = 1
then counter
else collatz (counter+1) (if is_even n then n/2 else 3*n+1);;
let () =
for i = 1 to 100 do
print_int (collatz 0 i);
print_newline ();
done;;
Doesn't that look nicer? Feel free to ask for any clarification of course.

Is there a way to make handling of Arrays in SML more pleasant?

When implementing algorithms in SML I often wonder if there is a simple way to make code that makes heavy use of arrays more readable. For instance if I define a SML function to swap 2 elements in an array, the code is ...
local open Array in
fun exch (a, i, j) =
let
val tmp = sub (a, i)
val _ = update (a, i, sub (a, j))
val _ = update (a, j, tmp)
in () end
end
What I would like to have is a more readable, cleaner Version like in this Scala-snippet ...
def exch[T](a: Array[T], i: Int, j: Int) {
val tmp = a(i)
a(i) = a(j)
a(j) = tmp
}
For something as simple as swapping 2 elements in an array, the SML version is okay. But as soon as the algorithms get more complex the code becomes more and more incomprehensible and does obfuscate the underlying algorithm.
A slightly more complex example would be this stack (implemented as resizable array) ...
structure ArrayStack = struct
type 'a stack = ('a option array * (int ref)) ref
exception Empty
fun mkStack () = ref (Array.array (1, NONE), ref 0)
fun isEmpty (ref (_, ref 0)) = true
| isEmpty _ = false
fun resize (array as ref (xs, n), capacity) =
let
val length = Array.length xs
in
array := (Array.tabulate (
capacity,
fn i => if i < length then Array.sub (xs, i) else NONE
), n)
end
fun push (array as ref (xs, n : int ref), x) =
if Array.length xs = !n then (
resize (array, !n*2)
; push (array, x))
else (
Array.update (xs, !n, SOME x)
; n := !n+1)
fun pop (ref (xs, ref 0)) = raise Empty
| pop (array as ref (xs, n : int ref)) = let
val _ = (n := !n-1)
val x = Array.sub (xs, !n)
val _ = Array.update (xs, !n, NONE)
val q = (Array.length xs) div 4
val _ = if !n > 0 andalso !n = q then resize (array, q) else ()
in
valOf x
end
end
By comparison with the java implementation at http://algs4.cs.princeton.edu/13stacks/ResizingArrayStack.java.html the implementation (especially of push/pop) becomes hard to read.
How can I make such code more readable?
It is true, arrays are rather awkward to use in SML. To some degree this is intentional, to discourage their use -- because most of the time, they are not the best choice of data structure. Your stack is a good example, since it is much better implemented as a list:
structure ListStack =
struct
type 'a stack = 'a list ref
fun stack () = ref nil
fun isEmpty s = List.null (!s)
fun push (s, x) = s := x::(!s)
fun pop s =
case !s of
nil => raise Empty
| x::xs => (s := xs; x)
end
(In fact, you wouldn't even normally do that, and avoid a stateful data structure like this altogether, using plain lists instead.)
If your concern is the allocation involved with lists, then note that (a) it is not doing more allocations than the array version (one :: instead of one SOME per push), and (b) allocations are very cheap in a language like SML.
But since your question is about using arrays, here is a slightly more idiomatic implementation of your array stack:
structure ArrayStack =
struct
open Array infix sub
datatype 'a stack = Stack of {data : 'a option array ref, size : int ref}
fun stack () = Stack {data = ref (array (1, NONE)), size = ref 0}
fun isEmpty (Stack {size, ...}) = !size = 0
fun resize (data, len') =
let val data' = array (len', NONE) in
copy {src = !data, dst = data', di = 0};
data := data'
end
fun push (Stack {data, size}, x) =
let val size' = !size + 1 in
if size' > length (!data) then resize (data, !size * 2) else ();
update (!data, !size, SOME x);
size := size'
end
fun pop (Stack {data, size}) =
if !size = 0 then raise Empty else
let
val _ = size := !size - 1
val x = !data sub (!size)
val q = length (!data) div 4
in
update (!data, !size, NONE);
if q > 0 andalso !size = q then resize (data, q) else ();
valOf x
end
end
In particular, I made sub infix, which allows you to write arr sub i. I did this just for demonstration, in this example it's not really worth it, with only one such usage.

What is wrong with this imperative version of factorial function in ocaml?

let impfac i =
let l = ref i in
let result = ref 1 in
let k = ref 2 in
while !k < !l do
result := !result * !k
k:=!k+1
done;
!result
The error message is:
let impfac i =
let l = ref i in
let result = ref 1 in
let k = ref 2 in
while !k < !l do
result := !result * !k
k:=!k+1
done;
!result;;
Characters 121-123:
result := !result * !k
^^
Error: This expression is not a function; it cannot be applied
#
result := !result * !k
k:=!k+1
You're missing a semicolon at the end of the first line. Because of this it is read as:
result := !result * (!k k:=!k+1)
i.e. it thinks you're trying to call !k with k:=!k+1 as its argument.
This is also why your editor indented the line with k := !k+1 farther to the right than the line above it. That should have been the first sign that something's wrong with the syntax.