SML function not accepting real list for comparison - sml

This function is part of a string of functions (for a course). It is supposed to take a list of reals [s,a,w,h], and check it against other lists of reals for equality. Those lists of reals are made from converting type racer objects (in the list R::acer) to real lists using racer_stats().
I then want the function to return the Racer that has stats that equal its racer_stats() stats. Unfortunately no matter what I try I cant figure out how to get SML to pattern match [s,a,w,h] as a real list so it will not compare, even when I made a new base case.
Any advice?
fun RFS([s,a,w,h], []) = None
| RFS([s,a,w,h], R::acer) =
if ( [s,a,w,h] = racer_stats(R) )
then R
else RFS([s,a,w,h], acer);
I also tried:
fun RFS( [0.1, 0.2, 0.3] , []) = None
| RFS([s,a,w,h], []) = None
| RFS([s,a,w,h], R::acer) =
if ( [s,a,w,h] = racer_stats(R) )
then R
else RFS([s,a,w,h], acer);
and got a syntax error.

Just in case anyone runs into this later. As molbdnilo pointed out reals are not an equality type. To workaround I built the following comparison operator:
fun compy([], []) = true
| compy([], x) = false
| compy(x, []) = false
| compy(x::xx, y::yy) = ( floor(x*100.0) = floor(y*100.0) ) andalso compy(xx, yy);
The *100.0 was because I wanted to compare to within 2 decimal places. I then swapped compy for =
fun RFS([s,a,w,h], []) = None
| RFS([s,a,w,h], R::acer) = if (compy([s,a,w,h], racer_stats(R)) ) then R
else RFS([s,a,w,h], acer);
Thanks to molbdnilo for pointing out that reals are not an equality type!

Related

How do you see if adjacent elements repeat in a list? (SML)

SML is a challenging language for me to learn. I'm trying to find a way to screen an undetermined list and return a boolean based on whether two elements adjacent on a list are the same value or not. What I've tried and think is close to correct is below.
fun repeatE nil = false
| repeatE (first::last) = first = last orelse repeatsE(last);
Obviously, this results in an error. I based my answer on this code, which tells me if a value is an element in the list.
fun member (e, nil) = false
| member (e, first::last) = e = first orelse member(e, last);
Why does the first one not work, but the last one does? It tells me that the operator and the operand don't agree, and maybe I'm thick-headed, but I don't quite understand why they don't?
Thank you in advance!
first=last tries to compare the first element of a list with the tail of that list, and you can only compare things of the same (comparable) type.
The working code works because it doesn't try to compare a list element to an entire list.
You need to compare the first element to the second element, and you need to handle the case of a singleton list.
Something like this:
fun repeats nil = false
| repeats (first::rest) = case rest of
(x::xs) => first = x orelse repeats rest
| _ => false
or
fun repeats nil = false
| repeats (first::rest) = not (null rest)
andalso (first = (hd rest) orelse repeats rest)
It's actually possible to use as to clean up #molbdnilo's answer a fair bit.
Ask yourself: An empty list is false, but so is a list with a single element, right?
fun repeats([]) = false
| repeats([_]) = false
Now, we need to match a list with at least two elements, and compare those. If they're not equal, we'll check everything but the first element.
fun repeats([]) = false
| repeats([_]) = false
| repeats(a::b::tail) =
a = b orelse repeats(b::tail)
But we don't need to use b::tail.
fun repeats([]) = false
| repeats([_]) = false
| repeats(a::(tail as b::_)) =
a = b orelse repeats(tail)
If we want, we can recognize that the empty list and the single element list are just the "other" when the last pattern doesn't match, and we'll rewrite it to reflect that.
fun repeats(a::(tail as b::_)) =
a = b orelse repeats(tail)
| repeats(_) = false

SML - Get Indices of List

I'm working on a program that appends either a '+' or '-' to an element of a list, depending on whether the index of that element is odd or even (i.e an alternating sums list).
However, I'm having trouble identifying what the index of each element is. I have code that I believe should append the correct symbol, using if statements and mod
fun alternating([]) = 0
| alternating(l) =
if List.nth(l,hd(l)) mod 2 == 0 then '+'#hd(l)#alternating(tl(l))
else '-'#hd(l)#alternating(tl(l))
However, List.nth(l,hd(l)) always returns the element at the second index, not the first.
On the off chance that you really just want to negate integers them so you can pass them into some kind of summation, I would just negate the argument if it's odd. Using mutual recursion one can do it without any explicit index bookkeeping:
fun alternate l =
let
fun alternate1 [] = []
| alternate1 (x::xs) = (~x) :: alternate2 xs
and alternate2 [] = []
| alternate2 (x::xs) = x :: alternate1 xs
in
alternate1 l
end
It works like so:
- alternate [1,2,3,4];
val it = [~1,2,~3,4] : int list
I would strongly encourage you to use pattern matching instead of hd.
Edit discussing hd
As a rule of thumb, if you need hd you probably need tl as well. hd is a partial function--it's going to throw Empty if your list is empty. If you pattern match, you conveniently get variables for the head and tail of the list right there, and you get a visual reminder that you need to handle the empty list. It's more aesthetically pleasing, IMO, to see:
fun foo [] = ...
| foo (x::xs) = ...
than the equivalent
fun foo l =
if null l
then ...
else (hd l) ... (tl l)
In other words, you get shorter, cleaner code with an automatic reminder to make it correct. Win/win. To my knowledge there's no significant advantage to doing it the other way. Of course, you may find yourself in a situation where you know the list will have at least one element and you don't need to do anything else. You still have to consider the cases you're given, but it's a good rule of thumb.
If you want to decorate your list with an index you could try something like the following
fun add_index l =
let
fun add_index_helper (nil, _) = nil
| add_index_helper (h::tl,i) = (h,i) :: add_index_helper (tl,1+i)
in
add_index_helper (l,0)
end
val x = add_index [0,1,4,9,16,25]
but you can also just directly compute parity with the same method
fun add_sign l =
let
fun add_sign_helper (nil, _) = nil
| add_sign_helper (h::tl,i) = (h,i) :: add_sign_helper (tl,1-i)
in
add_sign_helper (l,0)
end
val y = add_sign [0,1,4,9,16,25]
then you can map the parity to a string
fun sign_to_char (x,0) = (x,"+")
| sign_to_char (x,_) = (x,"-")
val z = List.map sign_to_char y
or you can just add the sign directly
fun add_char l =
let
fun add_char_helper (nil, _) = nil
| add_char_helper (h::tl,0) = (h,"+") :: add_char_helper (tl,1)
| add_char_helper (h::tl,_) = (h,"-") :: add_char_helper (tl,0)
in
add_char_helper (l,0)
end
val zz = add_char [0,1,4,9,16,25]
Alternatively if you had a string list and you wanted to add chars you could try something like this
fun signs L =
let
datatype parity = even | odd
fun signs_helper ( nil ,_) = nil
| signs_helper (x::xs,even) = ("+" ^ x) :: signs_helper(xs,odd)
| signs_helper (x::xs,odd) = ("-" ^ x) :: signs_helper(xs,even)
in
signs_helper (L,even)
end
val z = signs ["x","2y","3z","4"]
(* this gives you val z = ["+x","-2y","+3z","-4"] : string list *)

Checking for matching parenthesis

I am trying to write a code such that, given a list of parenthesis, I will check if the order is valid or not.
For simpleness, the follwoing datatype is defined.
datatype par = LPAR | RPAR
type pList = par list
What I have until now is:
fun valid(nil:plist): bool = true
| valid([Lpar]) = false
| valid([Rpar]) = false
| valid([Lrap,Rpar) = true
| valid(L::L1) =
For instance, "(()()"--> [Lpar,Lpar,Rpar,Lpar,Rpar] will return false
You can see that the parenthesis is in string format. I am confused since I will have to check to two things: that the left ( are equal to the left ) and that each ( matches a ). If so then I will need to make some helper functions.
Can you please provide me with information about what my helper functions should be or a better implementation of this?
ty
I have found out a way to solve my problem by counting the parenthesis. The logic goes like this:
I start from 0, if i find a left p I add 1, other wise I minus 1. Once I enter -1 i return false right away since I cannot have a right p come first. Then I recurse. If the final output is 0, the its true since this means that every left p matches a right p.
Q.E.D
I didn't try this in the repl but it should look something like this
fun valid_paren xs : bool =
fun aux (xs, ctr) = case xs of
[] => ctr = 0
| (x:xs') => case x of
'(' => aux (xs', ctr+1)
')' => aux (xs', ctr-1)
_ => aux (xs', ctr)
in
aux (xs, 0)

OCaml boolean expression [[]] == [[]]

I have a function that return [[]], and I want to test the result as unit test.
But I found that the expression [[]] == [[]] return false.
Here a simple test code:
# [[]] == [[]];;
- : bool = false
Can someone explain me why this expression is evaluated as false?
Thanks.
Use = since you have structural equality for comparing two values:
# [[]] = [[]];;
- : bool = true
Because == is reference equality, it only returns true if you refer to the same memory location:
let a = [[]]
let b = a
# b == a;;
- : bool = true
The == operator in OCaml means "physical equality". However, you have two (physically) different lists. Probably, you want "structural equality", which is tested by =.

Comparing list of floats

I wrote a code:
let rec compareVs v1 v2 =
if List.length v1 == 0 then
true
else
((match v1 with [] -> 0. | h::l -> h) == (match v2 with [] -> 0. | h::l -> h)) &&
(compareVs(match v1 with [] -> [] | h::l -> l) (match v2 with [] -> [] | h::l -> l))
And ran it:
# compareVs [0.1;0.1] [0.1;0.1];;
- : bool = false
Can't seem to find the problem. Please help.
EDIT
The problem seams to be with float comparisons:
# 0.1 == 0.1;;
- : bool = false
# 1.0 == 1.0;;
- : bool = false
How else can we compare floats in ocaml?
Use =, not ==.
Floats are reference types in ocaml and == checks reference equality. So 0.1 == 0.1 is false.
Generally, you almost always want to use =, not == to compare two values.
Note that aside from that, your function will return true for two lists of different size. Assuming that's not intended you should only return true when both lists are empty and false when one of them is empty and the other is not.
As a style note, using List.length to check whether a list is empty is usually a bad idea (for one thing it's O(n) even though it can be done in O(1) with pattern matching). Using pattern matching right at the beginning will also clean your code up a bit.
Like this:
let rec compareVs v1 v2 = match v1, v2 with
| [], [] -> true
| [], _
| _, [] -> false
| x::xs, y::ys -> x = y && compareVs xs ys
Oh and if this isn't just an exercise, note that you can just do v1 = v2 and don't actually need to write a function for this.
Sepp2k is correct, but as an additional discussion about comparing floats (which is often dangerous), the following functions have helped me:
This compares two floats with tolerance of epsilon and the syntax would be similar to other float functions. clearly extending >. and others is obvious.
let epsilon = 1.0e-10
let (=.) a b = (abs_float (a-.b)) < epsilon
If you are dealing with many extreme values of floats, you should look at the classify_float function in the pervasives module. I don't recall off the top of my head how NAN values are compared in the = function. You can independently experiment with this if you need to.
I had used this for awhile, but its tolerance was actually way to low for my usage (as in, a very small value for epsilon as above). This does not take into account what, NAN - NAN does. So, this might not be useful.
let (=.) a b = match classify_float ( a -. b ) with
| FP_infinite | FP_nan | FP_normal -> false
| FP_subnormal | FP_zero -> true