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 =.
Related
I am reading through the "Starting Out" chapter of Learn You a Haskell for Great Good!. It says:
null checks if a list is empty. If it is, it returns True, otherwise it returns False. Use this function instead of xs == [] (if you have a list called xs)
I tried in ghci:
xs = [] -- and then,
xs == []
null xs
Both of them are True.
I wonder what's the difference.
Should I use the null function instead of == [] and why?
You should use null. In most cases it doesn't matter, but it is a good habit to get into anyway, because occasionally you may want to check if a list of non-comparable things is empty. Here is a short, crisp example showing this difference:
> null [id]
False
> [id] == []
<interactive>:1:1: error:
• No instance for (Eq (a0 -> a0)) arising from a use of ‘==’
(maybe you haven't applied a function to enough arguments?)
• In the expression: [id] == []
In an equation for ‘it’: it = [id] == []
There is a difference. In order to use x == [], the type of the elements of the list should be a member of the Eq typeclass. Indeed, checking the equality of two lists is defined by the instance declaration:
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
That means that you can not use x == [] if x is for example a list of IO Ints.
null :: [a] -> Bool on the other hand, uses pattern matching. This is implemented as:
null :: [a] -> Bool
null [] = True
null (_:_) = False
So regardless what type the elements of the list are, it will always typecheck.
In addition to the good answers given so far, null actually has type
null :: Foldable t => t a -> Bool
I don't know if you've gotten to typeclasses in LYAH, but the short of it is that null can be used not just for lists, but for any data structure that implements null.
This is to say that using null on a Map or a Set is valid, too.
> null Map.empty
True
> null (Map.singleton 1)
False
> null Set.empty
True
> null (Set.singleton 1)
False
> null []
True
> null [1]
False
I don't think it's especially common to write functions that need to be this general, but it doesn't hurt to default to writing more general code.
A side note
In many cases, you'll end up wanting to use a function like null to do conditional behavior on a list (or other data structure). If you already know that your input is a specific data structure, it's more elegant to just pattern match on its empty case.
Compare
myMap :: (a -> b) -> [a] -> [b]
myMap f xs
| null xs = []
myMap f (x:xs) = f x : myMap f xs
to
myMap' :: (a -> b) -> [a] -> [b]
myMap' f [] = []
myMap' f (x:xs) = f x : myMap' f xs
In general, you should try to prefer pattern matching if it makes sense.
Also a simple function that filter all empty list would fail:
withoutEmpty = filter (== [])
and that would be:
withoutEmpty = filter null
notice that:
withoutEmpty ls = filter (==[]) ls
will work just fine, but the important point is that in some cases like the other one could fail.
Also look at #cole answer, it complements all the answers here, the typeclass Foldable has the null function there to be implemented:
To see more info of Foldable here
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!
I'm trying to determine if my hd(tl list) is nothing or not. hd(tl list) = ? What would I use on the other side of the equality symbol?
You can express the question 'is hd(tl list) nothing or not' as the equivalent question, 'does the list have less than two elements'. The latter question is easy to answer with SML in an elegant way using pattern matching on the list. Here is an interactive session:
$ poly
Poly/ML 5.7.1 Release
> fun isNothing [] = true
# | isNothing [_] = true
# | isNothing _ = false;
val isNothing = fn: 'a list -> bool
This function is saying, 'an empty list evaluates to true', 'a list with a single element evaluates to true', any other list evaluates to false. Tests:
> isNothing [];
val it = true: bool
> isNothing [1];
val it = true: bool
> isNothing [1, 2];
val it = false: bool
> isNothing [1, 2, 3];
val it = false: bool
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
It seems to be an equivalency comparison for some types, but not strings.
# 3 != 3;;
- : bool = false
# 3 != 2;;
- : bool = true
This is as expected.
# "odp" = "odp";;
- : bool = true
# "odp" != "odp";;
- : bool = true
# "odp" <> "odp";;
- : bool = false
Why does "odp" != "odp" evaluate to true? What is it actually doing? Shouldn't it generate a type error?
you have experienced the difference between structural and physical equality.
<> is to = (structural equality) as != is to == (physical equality)
"odg" = "odg" (* true *)
"odg" == "odg" (* false *)
is false because each is instantiated in different memory locations, doing:
let v = "odg"
v == v (* true *)
v = v (* true *)
Most of the time you'll want to use = and <>.
edit about when structural and physical equality are equivalent:
You can use the what_is_it function and find out all the types that would be equal both structurally and physically. As mentioned in the comments below, and in the linked article, characters, integers, unit, empty list, and some instances of variant types will have this property.
The opposite for != operator is == operator, not the = one.
# "a" != "a" ;;
- : bool = true
# "a" == "a" ;;
- : bool = false
The == operator is a "physical equality". When you type "a" == "a", you compare two different instances of strings that happen to look alike, so the operator returns false. While having one instance makes it return true:
# let str = "a"
in str == str ;;
- : bool = true
# let str = "a"
in str != str ;;
- : bool = false
A quick explanation about == and != in OCaml in addition to all the correct answers that have already been provided:
1/ == and != expose implementation details that you really don't want to know about. Example:
# let x = Some [] ;;
val x : 'a list option = Some []
# let t = Array.create 1 x ;;
val t : '_a list option array = [|Some []|]
# x == t.(0) ;;
- : bool = true
So far, so good: x and t.(0) are physically equal because t.(0) contains a pointer to the same block that x is pointing to. This is what basic knowledge of the implementation dictates. BUT:
# let x = 1.125 ;;
val x : float = 1.125
# let t = Array.create 1 x ;;
val t : float array = [|1.125|]
# x == t.(0) ;;
- : bool = false
What you are seeing here are the results of an otherwise useful optimization involving floats.
2/ On the other hand, there is a safe way to use ==, and that is as a quick but incomplete way to check for structural equality.
If you are writing an equality function on binary trees
let equal t1 t2 =
match ...
checking t1 and t2 for physical equality is a quick way to detect that they are obviously structurally equal, without even having to recurse and read them. That is:
let equal t1 t2 =
if t1 == t2
then true
else
match ...
And if you keep in mind that in OCaml the “boolean or” operator is “lazy”,
let equal t1 t1 =
(t1 == t2) ||
match ...
They are like two "Tom"s in your class! Because:
In this case, "odp" = "odp"
because they are TWO strings with SAME VALUE!!
So they are not == because they are TWO different strings store in different (Memory) location
They are = because they have the identical string value.
One more step deeper, "odp" is anonymous variable. And two anonymous variable leads to this Two strings.
For your convenience:
# "odp" = "odp";;
- : bool = true
# "odp" != "odp";;
- : bool = true
# "odp" <> "odp";;
- : bool = false
ints are the only type where physical and structural equality are the same, because ints are the only type that is unboxed