SML: why the return type is unit? - sml

So I have wrote a function (I will describe it briefly to avoid confusion)
fun function1 (l, a1,a2, suma, b2, sumb, d) =
while(a1<a2 andalso k>d) do
let
val k = Real.fromInt(a2-a1)
val suma = suma - Real.fromInt(List.nth(l, a1))
val sumb = sumb - Real.fromInt(List.nth(l, b2))
val a1 = a1+1
val b2 = b2-1
in
if suma<0.0 andalso ( (~sumf)/(N*k) )>1.0 andalso k>d
then k
else if sumb<0.0 andalso ((~sumb)/(N*k))>1.0 andalso k>d
then k
else d
end;
The system says this:
val function1 = fn : int list * int * int * real * int * real * real -> unit
I don't get the return type. I want to return a real like d & k . Why it's unit??

Related

Evaluation order of let-in expressions with tuples

My old notes on ML say that
let (๐‘ฃโ‚, โ€ฆ , ๐‘ฃโ‚™) = (๐‘กโ‚, โ€ฆ , ๐‘กโ‚™) in ๐‘กโ€ฒ
is a syntactic sugar for
(ฮป ๐‘ฃโ‚™. โ€ฆ (ฮป ๐‘ฃโ‚. ๐‘กโ€ฒ)๐‘กโ‚ โ€ฆ )๐‘กโ‚™
and that
let (๐‘ฃโ‚, ๐‘ฃโ‚‚) = ๐‘ก ๐‘กโ€ฒ in ๐‘กโ€ณ
is equivalent to
let ๐‘ฃ = ๐‘ก ๐‘กโ€ฒ in
let ๐‘ฃโ‚‚ = snd ๐‘ฃ in
let ๐‘ฃโ‚ = fst ๐‘ฃ in
๐‘กโ€ณ
where
each ๐‘ฃ (with or without a subscript) stands for a variable,
each ๐‘ก (with or without a sub- or a superscript) stands for a term, and
fst and snd deliver the first and second component of a pair, respectively.
I'm wondering whether I got the evaluation order right because I didn't note the original reference. Could anyone ((confirm or reject) and (supply a reference))?
It shouldn't matter whether it's:
let ๐‘ฃ = ๐‘ก ๐‘กโ€ฒ in
let ๐‘ฃโ‚‚ = snd ๐‘ฃ in
let ๐‘ฃโ‚ = fst ๐‘ฃ in
๐‘กโ€ณ
Or:
let ๐‘ฃ = ๐‘ก ๐‘กโ€ฒ in
let ๐‘ฃโ‚ = fst ๐‘ฃ in
let ๐‘ฃโ‚‚ = snd ๐‘ฃ in
๐‘กโ€ณ
Since neither fst nor snd have any side-effects. Side-effects may exist in the evaluation of ๐‘ก ๐‘กโ€ฒ but that's done before the let binding takes place.
Additionally, as in:
let (๐‘ฃโ‚, ๐‘ฃโ‚‚) = ๐‘ก ๐‘กโ€ฒ in ๐‘กโ€ณ
Neither ๐‘ฃโ‚ nor ๐‘ฃโ‚‚ is reliant on the value bound to the other to determine its value, so the order in which they're bound is again seemingly irrelevant.
All of that said, there may be an authoritative answer from those with deeper knowledge of the SML standard or the inner workings of OCaml's implementation. I simply am uncertain of how knowing it will provide any practical benefit.
Practical test
As a practical test, running some code where we bind a tuple of multiple expressions with side-effects to observe order of evaluation. In OCaml (5.0.0) the order of evaluation is observed to be right-to-left. We observe tthe same when it comes to evaluating the contents of a list where those expressions have side-effects as well.
# let f () = print_endline "f"; 1 in
let g () = print_endline "g"; 2 in
let h () = print_endline "h"; 3 in
let (a, b, c) = (f (), g (), h ()) in a + b + c;;
h
g
f
- : int = 6
# let f () = print_endline "f"; 1 in
let g () = print_endline "g"; 2 in
let h () = print_endline "h"; 3 in
let (c, b, a) = (h (), g(), f ()) in a + b + c;;
f
g
h
- : int = 6
# let f _ = print_endline "f"; 1 in
let g () = print_endline "g"; 2 in
let h () = print_endline "h"; 3 in
let a () = print_endline "a" in
let b () = print_endline "b" in
let (c, d, e) = (f [a (); b ()], g (), h ()) in
c + d + e;;
h
g
b
a
f
- : int = 6
In SML (SML/NJ v110.99.3) we observe the opposite: left-to-right evaluation of expressions.
- let
= fun f() = (print "f\n"; 1)
= fun g() = (print "g\n"; 2)
= fun h() = (print "h\n"; 3)
= val (a, b, c) = (f(), g(), h())
= in
= a + b + c
= end;
f
g
h
val it = 6 : int
- let
= fun f() = (print "f\n"; 1)
= fun g() = (print "g\n"; 2)
= fun h() = (print "h\n"; 3)
= val (c, b, a) = (h(), g(), f())
= in
= a + b + c
= end;
h
g
f
val it = 6 : int
- let
= fun f _ = (print "f\n"; 1)
= fun g() = (print "g\n"; 2)
= fun h() = (print "h\n"; 3)
= fun a() = print "a\n"
= fun b() = print "b\n"
= val (c, d, e) = (f [a(), b()], g(), h())
= in
= c + d + e
= end;
a
b
f
g
h
val it = 6 : int
Be aware that, in OCaml, due to the (relaxation of the) value restriction, let a = b in c is not equivalent to (fun a -> c)b. A counterexample is
# let id = fun x -> x in id 5, id 'a';;
- : int * char = (5, 'a')
# (fun id -> id 5, id 'a')(fun x -> x)
Error: This expression has type char but an expression was expected of type int
#
This means that they are semantically not the same construction (the let ... = ... in ... is strictly more general that the other).
This happens because, in general, the type system of OCaml doesn't allow types of the form (โˆ€ฮฑ.ฮฑโ†’ฮฑ) โ†’ int * char (because allowing them would make typing undecidable, which is not very practical), which would be the type of fun id -> id 5, id 'a'. Instead, it resorts to having the less general type โˆ€ฮฑ.(ฮฑโ†’ฮฑ) โ†’ ฮฑ * ฮฑ, which doesn't make it typecheck, because you can't unify both ฮฑ with char and with int.

Syntax error when Calling function inside function in Ocaml

I am getting a Syntax error when calling the function f and g inside lp and assigning them to y and z
let lp m =
let y = f m in
let z = g y (List.length y) m;
Here's my full code:
open Printf
open Format
let regraUm m = m/2
let regraDois m = ((m / 10) mod 10) * (m mod 10)
let regraTres m = 42
let f m =
let list = ref [] in
if ((m mod 2) = 0) then list := 1::!list;
if ((m mod 3) = 0) || ((m mod 4) = 0) then list := 2::!list;
if ((m mod 5) = 0) then list := 3::!list;
!list
let g list len m =
let res = ref [] in
for i = 0 to (len-1) do
let regra = List.nth list i in
if (regra = 1) then res := (m - (regraUm m))::!res;
if (regra = 2) || ((m mod 4) = 0) then res := (m - (regraDois m))::!res;
if (regra = 3) then res := (m - (regraTres m))::!res;
done;
!res
let lp m =
let y = f m in
let z = g y (List.length y) m;
Syntax Error:
ocamlopt regras.ml -o r
File "regras.ml", line 33, characters 4-4:
Error: Syntax error
f and g work properly when used outside of a function.
A let binding need some expression to be attached after an in, which in your case doesn't exist. In this case your code would work either adding z as expression or removing the binding leaving just the expression.
let lp m =
let y = f m in
let z = g y (List.length y) m in
z
Or this
let lp m =
let y = f m in
g y (List.length y) m

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;

How to do the Comparison of Two Functions

I would like to know how to compare two function F(x) & G(x) in SML, which two functions must return the same value that f(x)==g(x), where 1<= x <= 100.
For example:
- fun f x = x*x;
val f = fn : int -> int
- fun g x = x+x;
val g = fn : int -> int
- iden f g;
val it = false : bool
- fun f x = x*x;
val f = fn : int -> int
- fun g x = if x<0 then 0 else x*x;
val g = fn : int -> int
- iden f g;
val it = true : bool
Since testing whether or not two functions (programs) are equal for all inputs is not computable, your iden function will likely have to take more parameters than just the two functions that its comparing.
In general, your iden will be:
- fun iden f g elem = f(elem) = g(elem)
val iden = fn : ('a -> ''b) -> ('a -> ''b) -> 'a -> bool
In your specific case, you would probably want to do something like this:
- fun iden f g = let
= fun iden_h f g (a, b) =
= if a > b then iden_h f g (b, a)
= else if a = b then f(a) = g(a)
= else f(a) = g(a) andalso iden_h f g (a+1, b)
= in
= iden_h f g (1, 100)
= end
val iden = fn : (int -> ''a) -> (int -> ''a) -> bool
-
- iden (fn x => x + x) (fn x => 2 * x);
val it = true : bool
- iden (fn x => x + x) (fn x => x * x);
val it = false : bool

Doing a N-dimensional walk in pure functional ML?

The idea is to walk over multiple dimensions, each one defined as a range
(* lower_bound, upper_bound, number_of_steps *)
type range = real * real * int
so functions like fun foo y x or fun foo z y x could be applied to the whole square XY or cube XY*Z.
SML/NJ doesn't like my implementation below :
test2.sml:7.5-22.6 Error: right-hand-side of clause doesn't agree with function result type [circularity]
expression: (real -> 'Z) -> unit
result type: 'Z -> 'Y
in declaration:
walk = (fn arg => (fn <pat> => <exp>))
Here's the code :
fun walk [] _ = ()
| walk (r::rs) f =
let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k =
let in
walk rs (f k) ; (* Note (f k) "eats" the first argument.
I guess SML doesn't like having the
type of walk change in the middle of its
definition *)
loop (i - 1) (k + step)
end
in
loop n k0
end
fun do2D y x = (* ... *) ()
fun do3D z y x = (* ... *) ()
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val _ = walk [y_axis, x_axis] do2D
val _ = walk [z_axis, y_axis, x_axis] do3D
Is this kind of construct even possible ?
Any pointer welcomed.
Is walk expressible in ML's type system?
val walk : range list -> (real -> real -> unit) -> unit
val walk : range list -> (real -> real -> real -> unit) -> unit
The same one value cannot possibly exist with both those types in ML.
We can easily generate values for each of the desired types, though.
type range = real * real * int
signature WALK =
sig
type apply
val walk : range list -> apply -> unit
end
structure Walk0 : WALK =
struct
type apply = unit
fun walk _ _ = ()
end
functor WALKF (Walk : WALK) : WALK =
struct
type apply = real -> Walk.apply
fun walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (Walk.walk rs (f x); loop (i + 1)) end
in loop 0 end
end
struture Walk1 = WALKF(Walk0)
struture Walk2 = WALKF(Walk1)
struture Walk3 = WALKF(Walk2)
With this, the following values exist with the desired types.
val Walk0.walk : range list -> unit -> unit
val Walk1.walk : range list -> (real -> unit) -> unit
val Walk2.walk : range list -> (real -> real -> unit) -> unit
val Walk3.walk : range list -> (real -> real -> real -> unit) -> unit
Then you only need to write
val _ = Walk2.walk [y_axis, x_axis] do2D
val _ = Walk3.walk [z_axis, y_axis, x_axis] do3D
To use the same walk for every dimensionality, you need it to use the same type for every dimensionality.
fun walk nil f = f nil
| walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (walk rs (fn xs -> f (x::xs)); loop (i + 1)) end
in loop 0 end
Because the type is changed to
val walk : range list -> (real list -> unit) -> unit
your usage also has to change to
fun do2D [y,x] = (* ... *) ()
fun do3D [z,y,x] = (* ... *) ()
fun walk lst f = let
fun aux rev_prefix [] = f (rev rev_prefix)
| aux rev_prefix (r::rs) = let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k = (
aux (k+step :: rev_prefix) rs;
loop (i - 1) (k + step)
)
in
loop n k0
end
in
aux [] lst
end
fun do2D [x,y] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\n")
fun do3D [x,y,z] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\t" ^
Real.toString z ^ "\n")
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val () = walk [y_axis, x_axis] do2D
val () = walk [z_axis, y_axis, x_axis] do3D
Found this implementation for variable number of arguments. Not sure it applies but it looks quite ugly.